Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell vs. erlang: difference in foldl?

I've noticed there's a difference between Haskell and Erlang when it comes to foldl.

For foldr, both languages return the same results:

foldr (\x y -> 2*x+y) 4 [1, 2, 3] -- returns 49
lists:foldr(fun(X, Y) −> X+2∗Y end, 4, [1,2,3]). % returns 49

But the return values for foldl are different:

foldl (\x y -> x+2*y) 4 [1, 2, 3] -- returns 16
lists:foldl(fun(X, Y) −> X+2∗Y end, 4, [1,2,3]). -- returns 43

How can this difference be explained?

like image 377
TheLeonKing Avatar asked Dec 12 '15 10:12

TheLeonKing


People also ask

What does foldl do Haskell?

Haskell : foldl. Description: it takes the second argument and the first item of the list and applies the function to them, then feeds the function with this result and the second argument and so on. See scanl for intermediate results.

Is foldl or foldr better?

Only foldr is lazy and can be used for codata/infinite streams. While foldl is tail-recursive (enhanced with strict application foldl' can avoid stack overflow). This is why foldr should be used by default in Haskellin order preserve laziness across function composition.

How does foldl work?

For foldl you need to switch the argument order between acc and _ , because foldr logically puts the initial argument on the end of the sequence, while foldl puts it logically at the start. That means that the accumulator is the first (!) argument to the folding function for foldl (and the second argument for foldr ).

What does foldr do?

To recap, with foldr , the purpose of the function argument is to take the first element of the list and the results of having folded the rest of the list, and return the new value. With foldl , the function argument takes a default value, the first element of the list, and returns a new default value.


1 Answers

You are confusing yourself by not simplifying your fold function.

fold left, Haskell:

Prelude Debug.Trace> foldl (\x y -> trace("x:"++show x++" y:"++show y) $ x+y) 4 [1,2,3]
x:4 y:1
x:5 y:2
x:7 y:3
10

fold left, Erlang:

1> lists:foldl(fun (X,Y) -> io:format("x:~p y:~p~n", [X,Y]), X+Y end, 4, [1,2,3]).
x:1 y:4
x:2 y:5
x:3 y:7
10

fold right, Haskell:

Prelude Debug.Trace> foldr (\x y -> trace("x:"++show x++" y:"++show y) $ x+y) 4 [1,2,3]
x:3 y:4
x:2 y:7
x:1 y:9
10

fold right, Erlang:

2> lists:foldr(fun (X,Y) -> io:format("x:~p y:~p~n", [X,Y]), X+Y end, 4, [1,2,3]).
x:3 y:4
x:2 y:7
x:1 y:9
10

From this, it's clear that in Haskell, the foldl function will be passed (Accumulator, Element) while the foldr function will be passed (Element, Accumulator). On the other hand, both functions in Erlang will be passed (Element, Accumulator).

like image 110
Nathaniel Waisbrot Avatar answered Nov 11 '22 04:11

Nathaniel Waisbrot