1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
-- How many of the following Prelude functions can you rewrite using list folds?
--
-- - any
-- - cycle
-- - words
-- - unlines
--
-- For those functions where you can use either foldl' or foldr, which is more
-- appropriate in each case?
-- Let's assume that rewriting here means using a fold function as the top-level
-- function, using its output directly as an output of a rewritten function, and
-- not using any recursion in the fold's step function.
--
-- "Appropriate" is a vague term. It can mean appropriate with regards to
-- - processing an infinite input list, or
-- - lazy evaluation in the case of a finite input list, not evaluating
-- subexpressions when not necessary, or
-- - learning/teaching purpose, or
-- - natural way of thinking about the problem to solve (e.g, people
-- usually read books from the first page to the last one, not the other way
-- around), or
-- - ...
--
-- For deciding between foldl' and foldr, let's assume only finite input lists.
-- References:
--
-- - This article helped me to understand how lazy evaluation works with foldr
-- https://elbauldelprogramador.com/org-posts/foldr-infinite-list-haskell.html
-- - Description of the words function
-- https://hackage.haskell.org/package/base-4.18.0.0/docs/Prelude.html#v:words
-- - Description of the unlines function
-- https://hackage.haskell.org/package/base-4.18.0.0/docs/Prelude.html#v:unlines
import Data.Char
-- Let's use foldr. It enables short-circuit evaluation, not continuing in
-- evaluation of the rest of the input if the first value for which the f
-- function is true is found.
myAny :: (a -> Bool) -> [a] -> Bool
myAny f xs = foldr op False xs
where op x acc = if f x
then True
else acc
-- ghci> :l 4_b_10.hs
-- [1 of 1] Compiling Main ( 4_b_10.hs, interpreted )
-- Ok, one module loaded.
-- ghci> any odd []
-- False
-- ghci> any odd [2, 4, 6, 8]
-- False
-- ghci> any odd [2, 4, 7, 8]
-- True
-- ghci> myAny odd []
-- False
-- ghci> myAny odd [2, 4, 6, 8]
-- False
-- ghci> myAny odd [2, 4, 7, 8]
-- True
-- The cycle function cannot be rewritten using the list folds. It outputs an
-- infinite list. The input is a finite list. For a finite list, the step
-- function is called finite number of times, so without using recursion, it is
-- not possible to generate an infinite output.
-- The words function cannot be rewritten using the list folds. For example, the
-- function must be able to transform " foo bar " into ["foo", "bar"]. With
-- using fold as we defined it for this exercise, it is not possible to handle
-- trailing (or leading; depending on whether we use foldl' or foldr) spaces. It
-- would be possible if we allowed post-processing the output of the fold,
-- trimming the trailing empty string.
--
-- Without post-processing, we have to find a way of not adding a trailing empty
-- string into the output for the trailing spaces in the input. This could be
-- done either by adding the empty string only after encountering a non-space
-- character (and putting that character into that empty string), or by adding
-- it when encountering a space character (correctly handling multiple
-- successive spaces).
--
-- With the first option, we would have to ignore input spaces because we expect
-- a new empty string to be added to the output on a non-space input character,
-- but this would result in putting every non-space character into its own
-- output list.
--
-- With the second option, we would add an empty list into the output for the
-- last trailing space, but it would stay empty in the output when there is no
-- non-space character to be put into that list.
-- Let's use foldr to take advantage of lazy evaluation.
myUnlines :: [String] -> String
myUnlines xs = foldr op [] xs
where op x acc = x ++ "\n" ++ acc
-- ghci> unlines []
-- ""
-- ghci> unlines ["abc","","","def "]
-- "abc\n\n\ndef \n"
-- ghci> myUnlines []
-- ""
-- ghci> myUnlines ["abc","","","def "]
-- "abc\n\n\ndef \n"
|