Can anybody explain how foldr
works?
Take these examples:
Prelude> foldr (-) 54 [10,11]
53
Prelude> foldr (\x y -> (x+y)/2) 54 [12,4,10,6]
12.0
I am confused about these executions, any suggestions?
Can anybody explain how foldr
works?
Take these examples:
Prelude> foldr (-) 54 [10,11]
53
Prelude> foldr (\x y -> (x+y)/2) 54 [12,4,10,6]
12.0
I am confused about these executions, any suggestions?
Think about foldr's very definition:
-- if the list is empty, the result is the initial value z
foldr f z [] = z
-- if not, apply f to the first element and the result of folding the rest
foldr f z (x:xs) = f x (foldr f z xs)
So for example foldr (-) 54 [10,11]
must equal (-) 10 (foldr (-) 54 [11])
, i.e. expanding again, equal (-) 10 ((-) 11 54)
. So the inner operation is 11 - 54
, that is, -43; and the outer operation is 10 - (-43)
, that is, 10 + 43
, therefore 53
as you observe. Go through similar steps for your second case, and again you'll see how the result forms!
foldr
begins at the right-hand end of the list and combines each list entry with the accumulator value using the function you give it. The result is the final value of the accumulator after "folding" in all the list elements. Its type is:
foldr :: (a -> b -> b) -> b -> [a] -> b
and from this you can see that the list element (of type a
) is the first argument to the given function, and the accumulator (of type b
) is the second.
For your first example:
Starting accumulator = 54
11 - 54 = -43
10 - (-43) = 53
^ Result from the previous line
^ Next list item
So the answer you got was 53.
The second example:
Starting accumulator = 54
(6 + 54) / 2 = 30
(10 + 30) / 2 = 20
(4 + 20) / 2 = 12
(12 + 12) / 2 = 12
So the result is 12.
Edit: I meant to add, that's for finite lists. foldr
can also work on infinite lists but it's best to get your head around the finite case first, I think.
I've always thought http://foldr.com to be a fun illustration. See the Lambda the Ultimate post.
The easiest way to understand foldr is to rewrite the list you're folding over without the sugar.
[1,2,3,4,5] => 1:(2:(3:(4:(5:[]))))
now what foldr f x does is that it replaces each : with f in infix form and [] with x and evaluates the result.
For example:
sum [1,2,3] = foldr (+) 0 [1,2,3]
[1,2,3] === 1:(2:(3:[]))
so sum [1,2,3] === 1+(2+(3+0)) = 6
An easy way to understand foldr is this: It replaces every list constructor with an application of the function provided. Your first example would translate to:
10 - (11 - 54)
from:
10 : (11 : [])
A good piece of advice that I got from the Haskell wikibook might be of some use here:
As a rule you should use foldr on lists that might be infinite or where the fold is building up a data structure, and foldl' if the list is known to be finite and comes down to a single value. foldl (without the tick) should rarely be used at all.