I am new to haskell and I would like you to give me your suggestion about the following haskell expression evaluation.
f xs = foldr (\x n->n+1) 0 xs
function
f [1, 4]
Evaluation
(\x n->n+1) 1 (foldr (\x n->n+1) 0 [4])
= (foldr (\x n->n+1) 0 [4]) + 1
= ((\x n->n+1) 4 (foldr (\x n->n+1) 0 [4])) + 1
= (foldr (\x n->n+1) 0 [] + 1) + 1
= (0 + 1) + 1
= 1 + 1
= 2
First of all we need the foldr implementation:
foldr f z [] = z
foldr f z (x:xs) = f x (foldr f z xs)
now let's try to "trace" our computation f [1, 4]:
f [1, 4] -- rewrite list
f (1:(4:[])) -- replace f function where xs = (1:(4:[]))
foldr (\x n-> (+) n 1 ) 0 (1:(4:[]))
-- using foldr f z (x:xs) = f x (foldr f z xs)
-- where f = (\x n -> (+) n 1), z = 0, x = 1, xs = (4:[])
(\x n ->(+) n 1) 1 ( foldr (\x n -> (+) n 1) 0 (4:[]))
-- lambda function will be evaluated with x = 1, n = ( foldr (\x n -> n+1) 0 (4:[]))
(+) (foldr (\x n -> n+1) 0 (4:[])) 1
-- (+) will try to evaluate first parameter
-- foldr will be applied with f = (\x n -> (+) n 1), z = 0, x = 4, xs = []
(+) ((\x n -> (+) n 1) 4 (foldr (\x n -> (+) n 1) 0 [] )) 1
-- now again the lambda will be evaluated where x = 4 and n = (foldr (\x n -> (+) n 1) 0 [] )
(+) ( (+) (foldr (\x n -> (+) n 1) 0 [] ) 1 ) 1
-- now foldr will be evaluated again but this time first form will be used, so just z counts: f = (\x n -> (+) n 1), z = 0, [] = []
(+) ( (+) ( 0 ) 1 ) 1
-- now just go with the flow
(+) ( (+) 0 1 ) 1
(+) ( 1 ) 1
(+) 1 1
2
Related
Since I am new in "innermost, outermost" I have problem with understanding the leftmost outermost style.
I would like to understand the reduction processes for the list [5,2,1]
foldl :: ( b -> a -> b ) -> b -> [ a ] -> b
foldl _ e [] = e
foldl f e (x:xs) = foldl f (f e x) xs
foldl (\acc x -> acc ++ [negate x]) [] [5,2,1]
You can inline the definition to get a better understanding of what is going on.
foldl (\acc x -> acc ++ [negate x]) [] [5,2,1]
-- using foldl f e (x:xs) = foldl f (f e x) xs
-- with f = (\acc x -> acc ++ [negate x])
-- e = []
-- x = 5
-- xs = [2,1]
-- replace line 1 with foldl f (f e x) xs
foldl f (f [] 5) [2,1]
foldl f (f (f [] 5) 2) [1]
foldl f (f (f (f [] 5) 2) 1) []
-- using foldl _ e [] = e
f (f (f [] 5) 2) 1
-- in infix style (f [] 5 == [] `f` 5)
(([] `f` 5) `f` 2) `f` 1
In general
foldl (+) 0 [a, b, c] == ((0 + a) + b) + c
foldr (+) 0 [a, b, c] == a + (b + (c + 0))
Having a hard time understanding fold... Is the expansion correct ? Also would appreciate any links, or analogies that would make fold more digestible.
foldMap :: (a -> b) -> [a] -> [b]
foldMap f [] = []
foldMap f xs = foldr (\x ys -> (f x) : ys) [] xs
b = (\x ys -> (f x):ys)
foldMap (*2) [1,2,3]
= b 1 (b 2 (foldr b [] 3))
= b 1 (b 2 (b 3 ( b [] [])))
= b 1 (b 2 ((*2 3) : []))
= b 1 ((*2 2) : (6 :[]))
= (* 2 1) : (4 : (6 : []))
= 2 : (4 : (6 : []))
First, let's not use the name foldMap since that's already a standard function different from map. If you want to re-implement an existing function with the same or similar semantics, convention is to give it the same name but either in a separate module, or with a prime ' appended to the name. Also, we can omit the empty-list case, since you can just pass that to the fold just as well:
map' :: (a -> b) -> [a] -> [b]
map' f xs = foldr (\x ys -> f x : ys) [] xs
Now if you want to evaluate this function by hand, first just use the definition without inserting anything more:
map' (*2) [1,2,3,4]
≡ let f = (*2)
xs = [1,2,3,4]
in foldr (\x ys -> (f x) : ys) [] xs
≡ foldr (\x ys -> (*2) x : ys) [] [1,2,3,4]
Now just prettify a bit:
≡ foldr (\x ys -> x*2 : ys) [] [1,2,3,4]
Now to evaluate this through, you also need the definition of foldr. It's actually a bit different in GHC, but effectively
foldr _ z [] = z
foldr f z (x:xs) = f x (foldr f z xs)
So with your example
...
≡ foldr (\x ys -> x*2 : ys) [] (1:[2,3,4])
≡ (\x ys -> x*2 : ys) 1 (foldr (\x ys -> x*2 : ys) [] [2,3,4])
Now we can perform a β-reduction:
≡ 1*2 : foldr (\x ys -> x*2 : ys) [] [2,3,4]
≡ 2 : foldr (\x ys -> x*2 : ys) [] [2,3,4]
...and repeat for the recursion.
foldr defines a family of equations,
foldr g n [] = n
foldr g n [x] = g x (foldr g n []) = g x n
foldr g n [x,y] = g x (foldr g n [y]) = g x (g y n)
foldr g n [x,y,z] = g x (foldr g n [y,z]) = g x (g y (g z n))
----- r ---------
and so on. g is a reducer function,
g x r = ....
accepting as x an element of the input list, and as r the result of recursively processing the rest of the input list (as can be seen in the equations).
map, on the other hand, defines a family of equations
map f [] = []
map f [x] = [f x] = (:) (f x) [] = ((:) . f) x []
map f [x,y] = [f x, f y] = ((:) . f) x (((:) . f) y [])
map f [x,y,z] = [f x, f y, f z] = ((:) . f) x (((:) . f) y (((:) . f) z []))
= (:) (f x) ( (:) (f y) ( (:) (f z) []))
The two families simply exactly match with
g = ((:) . f) = (\x -> (:) (f x)) = (\x r -> f x : r)
and n = [], and thus
foldr ((:) . f) [] xs == map f xs
We can prove this rigorously by mathematical induction on the input list's length, following the defining laws of foldr,
foldr g n [] = []
foldr g n (x:xs) = g x (foldr g n xs)
which are the basis for the equations at the top of this post.
Modern Haskell has Fodable type class with its basic fold following the laws of
fold(<>,n) [] = n
fold(<>,n) (xs ++ ys) = fold(<>,n) xs <> fold(<>,n) ys
and the map is naturally defined in its terms as
map f xs = foldMap (\x -> [f x]) xs
turning [x, y, z, ...] into [f x] ++ [f y] ++ [f z] ++ ..., since for lists (<>) == (++). This follows from the equivalence
f x : ys == [f x] ++ ys
This also lets us define filter along the same lines easily, as
filter p xs = foldMap (\x -> [x | p x]) xs
To your specific question, the expansion is correct, except that (*2 x) should be written as ((*2) x), which is the same as (x * 2). (* 2 x) is not a valid Haskell (though valid Lisp :) ).
Functions like (*2) are known as "operator sections" -- the missing argument goes into the empty slot: (* 2) 3 = (3 * 2) = (3 *) 2 = (*) 3 2.
You also asked for some links: see e.g. this, this and this.
I've been trying to wrap my head around foldr and foldl for quite some time, and I've decided the following question should settle it for me. Suppose you pass the following list [1,2,3] into the following four functions:
a = foldl (\xs y -> 10*xs -y) 0
b = foldl (\xs y -> y - 10 * xs) 0
c = foldr (\y xs -> y - 10 * xs) 0
d = foldr (\y xs -> 10 * xs -y) 0
The results will be -123, 83, 281, and -321 respectively.
Why is this the case? I know that when you pass [1,2,3,4] into a function defined as
f = foldl (xs x -> xs ++ [f x]) []
it gets expanded to ((([] ++ [1]) ++ [2]) ++ [3]) ++ [4]
In the same vein, What do the above functions a, b, c, and d get expanded to?
I think the two images on Haskell Wiki's fold page explain it quite nicely.
Since your operations are not commutative, the results of foldr and foldl will not be the same, whereas in a commutative operation they would:
Prelude> foldl1 (*) [1..3]
6
Prelude> foldr1 (*) [1..3]
6
Using scanl and scanr to get a list including the intermediate results is a good way to see what happens:
Prelude> scanl1 (*) [1..3]
[1,2,6]
Prelude> scanr1 (*) [1..3]
[6,6,3]
So in the first case we have (((1 * 1) * 2) * 3), whereas in the second case it's (1 * (2 * (1 * 3))).
foldr is a really simple function idea: get a function which combines two arguments, get a starting point, a list, and compute the result of calling the function on the list in that way.
Here's a nice little hint about how to imagine what happens during a foldr call:
foldr (+) 0 [1,2,3,4,5]
=> 1 + (2 + (3 + (4 + (5 + 0))))
We all know that [1,2,3,4,5] = 1:2:3:4:5:[]. All you need to do is replace [] with the starting point and : with whatever function we use. Of course, we can also reconstruct a list in the same way:
foldr (:) [] [1,2,3]
=> 1 : (2 : (3 : []))
We can get more of an understanding of what happens within the function if we look at the signature:
foldr :: (a -> b -> b) -> b -> [a] -> b
We see that the function first gets an element from the list, then the accumulator, and returns what the next accumulator will be. With this, we can write our own foldr function:
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr f a [] = a
foldr f a (x:xs) = f x (foldr f a xs)
And there you are; you should have a better idea as to how foldr works, so you can apply that to your problems above.
The fold* functions can be seen as looping over the list passed to it, starting from either the end of the list (foldr), or the start of the list (foldl). For each of the elements it finds, it passes this element and the current value of the accumulator to what you have written as a lambda function. Whatever this function returns is used as the value of the accumulator in the next iteration.
Slightly changing your notation (acc instead of xs) to show a clearer meaning, for the first left fold
a = foldl (\acc y -> 10*acc - y) 0 [1, 2, 3]
= foldl (\acc y -> 10*acc - y) (0*1 - 1) [2, 3]
= foldl (\acc y -> 10*acc - y) -1 [2, 3]
= foldl (\acc y -> 10*acc - y) (10*(-1) - 2) [3]
= foldl (\acc y -> 10*acc - y) (-12) [3]
= foldl (\acc y -> 10*acc - y) (10*(-12) - 3) []
= foldl (\acc y -> 10*acc - y) (-123) []
= (-123)
And for your first right fold (note the accumulator takes a different position in the arguments to the lambda function)
c = foldr (\y acc -> y - 10*acc) 0 [1, 2, 3]
= foldr (\y acc -> y - 10*acc) (3 - 10*0) [1, 2]
= foldr (\y acc -> y - 10*acc) 3 [1, 2]
= foldr (\y acc -> y - 10*acc) (2 - 10*3) [1]
= foldr (\y acc -> y - 10*acc) (-28) [1]
= foldr (\y acc -> y - 10*acc) (1 - 10*(-28)) []
= foldr (\y acc -> y - 10*acc) 281 []
= 281
Could you explain me step by step the result of the second instruction?
I know how foldr works in this cases:
foldr (*) 1 [-3..-1]
-6
But I don't know how to deal with the function (\y z -> y*3 + z) in a foldr expression.
foldr (\y z -> y*3 + z) 0 [1..4]
30
Let's look at the definition of foldr:
foldr f z [] = z
foldr f z (x:xs) = f x (foldr f z xs)
Now, in your example,
f y z = y*3 + z
So, just using the definitions:
foldr f 0 [1..4] =
f 1 (foldr f 0 [2..4]) =
f 1 (f 2 (foldr f 0 [3,4])) =
f 1 (f 2 (f 3 (foldr f 0 [4]))) =
f 1 (f 2 (f 3 (f 4 (foldr f 0 [])))) =
f 1 (f 2 (f 3 (f 4 0))) =
f 1 (f 2 (f 3 12))) =
f 1 (f 2 21) =
f 1 27 =
30
Let's say I have the following function:
sumAll :: [(Int,Int)] -> Int
sumAll xs = foldr (+) 0 (map f xs)
where f (x,y) = x+y
The result of sumAll [(1,1),(2,2),(3,3)] will be 12.
What I don't understand is where the (x,y) values are coming from. Well, I know they come from the xs variable but I don't understand how. I mean, doing the code above directly without the where keyword, it would be something like this:
sumAll xs = foldr (+) 0 (map (\(x,y) -> x+y) xs)
And I can't understand, in the top code, how does the f variable and (x,y) variables represent the (\(x,y) -> x+y) lambda expression.
Hopefully this will help. The key is that f is applied to the elements of the list, which are pairs.
sumAll [(1,1),(2,2),(3,3)]
-- definition of sumAll
= foldr (+) 0 (map f [(1,1),(2,2),(3,3)])
-- application of map
= foldr (+) 0 (f (1,1) : map f [(2,2),(3,3)])
-- application of foldr
= 0 + foldr (+) (f (1,1)) (map f [(2,2),(3,3)])
-- application of map
= 0 + foldr (+) (f (1,1)) (f (2,2) : map f [(3,3)])
-- application of foldr
= 0 + (f (1,1) + foldr (+) (f (2,2)) (map f [(3,3)]))
-- application of f
= 0 + (2 + foldr (+) (f (2,2)) (map f [(3,3)]))
-- application of map
= 0 + (2 + foldr (+) (f (2,2)) (f (3,3) : map f []))
-- application of foldr
= 0 + (2 + (f (2,2) + foldr (+) (f (3,3)) (map f [])))
-- application of f
= 0 + (2 + (4 + foldr (+) (f (3,3)) (map f [])))
-- application of map
= 0 + (2 + (4 + foldr (+) (f (3,3)) []))
-- application of foldr
= 0 + (2 + (4 + f (3,3)))
-- application of f
= 0 + (2 + (4 + 6))
= 0 + (2 + 10)
= 0 + 12
= 12
In Haskell, functions are first class datatypes.
This means you can pass functions around like other types of data such as integers and strings.
In your code above you declare 'f' to be a function, which takes in one argumenta (a tuple of two values (x,y)) and returns the result of (x + y).
foldr is another function which takes in 3 arguments, a binary function (in this case +) a starting value (0) and an array of values to iterator over.
In short 'where f (x,y) = x + y' is just scoped shorthand for
sumAll :: [(Int,Int)] -> Int
sumAll xs = foldr (+) 0 (map myFunctionF xs)
myFunctionF :: (Int,Int) -> Int
myFunctionF (x,y) = x + y
Edit: If your unsure about how foldr works, check out Haskell Reference Zvon
Below is an example implementation of foldl / map.
foldl :: (a -> b -> b) -> b -> [a] -> b
foldl _ x [] = x
foldl fx (y:ys) = foldl f (f y x) ys
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = (f x) : (map f xs)
Not an answer, but I thought I should point out that your function f:
f (x, y) = x + y
can be expressed as
f = uncurry (+)