tags:

views:

399

answers:

6
+6  Q: 

How foldr works

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?

+5  A: 
Jeff Foster
+7  A: 

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!

Alex Martelli
+14  A: 

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.

Nefrubyr
Are you sure foldr can work on infinite lists? By my understanding the brackets mean it has to evaluate the last element first.
Jeff Foster
You can implement 'map', for example, using foldr, and that will work even on infinite lists. This works because (:) is non-strict in its second argument, or in English, because the tail of the result list can remain unevaluated as you walk along it. There are plenty of web pages around that explain this better than I can, but as I said, it takes some effort to get your head around it. Reconciling how foldr *behaves* and how it's *defined* is not trivial.
Nefrubyr
+1  A: 

I've always thought http://foldr.com to be a fun illustration. See the Lambda the Ultimate post.

Steven Huwig
those links seem to be dead. Any idea what happened?
Dan
It was dead when he posted the link, IIRC.
Rayne
Yes, they seem to have died quite recently.
Steven Huwig
+5  A: 

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
Tirpen
+1  A: 

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.

Rayne