Haskell Lazy Evaluation and Rewriting - haskell

Function Definitions:
first_threes :: [Int] -- first three numbers repeated
first_threes = 1:2:3:first_threes -- th.1
take :: Int -> [a] -> [a] -- take
take 0 _ = [] -- t.1
take n (x:xs) = x : (take (n - 1) xs) -- t.2
sum :: [Int] -> Int -- summation of an Int list
sum [] = 0 -- s.1
sum (x:xs) = x + (sum xs) -- s.2
I need to rewrite the statement below by using the definitions of the functions above. I need to obtain the answer 9. I need to justify each solution using 'Lazy Evaluation'.
Hugs_Main> my sum (my take 5 first_threes)
9
I am trying to work out 20 solutions which obtain 9 as the answer. Below are my first 10 solutions but I cannot think of anything else. Can anyone help out?
My first 10 solutions:
my_sum (my_take 5 first_threes)
my_sum (my_take 5 (1:2:3:first_threes))
my_sum (my_take 5 (1:2:first_threes))
my_sum (my_take 5 (2:first_threes))
my_sum (my_take 4 (3:first_threes))
my_sum (1:2:3:(my_take 2 (first_threes)))
my_sum (1:2:(my_take 3 (first_threes)))
my_sum (1:(2:my_take 3 (3:first_threes)))
my_sum (1:(my_take 4 (2:3:first_threes)))
my_sum (1:(my_take 4 (2:first_threes)))

I think this starts what your teacher wants to see
my_sum (my_take 5 first_threes)
-- th.1
my_sum (my_take 5 (1:2:3:first_threes))
-- t.2
my_sum (1 : my_take 4 (2:3:first_threes))
-- s.2
1 + my_sum (my_take 4 (2:3:first_threes))
-- continue yourself
A word on nomenclature: Check whether you have to work through solutions. I gave you a few rewrites. In every step you use one of the equalities to rewrite your term. The comments indicate which on I used for rewrite..

-- original expression
sum (take 5 first_threes)
-- (substitution) apply `take 5 first_threes` to `sum`
case take 5 first_threes of
[] -> 0
(x : xs) -> x + sum xs
-- pattern matching force evaluation of the first cons constructor so
-- we need eval `take 5 first_threes` first
-- apply `first_threes` to `take n` (substitution)
(\ n -> case n of
0 -> []
_ -> case first_trees of
_ -> []
(x : xs) -> x : take (n - 1) xs) 5
-- apply 5 to the lambda (substitution)
case 5 of
0 -> []
_ -> case first_trees of
_ -> []
(x : xs) -> x : take (5 - 1) xs
-- 5 is already in normal form, after case analysis we will have
case first_trees of
_ -> []
(x : xs) -> x : take (5 - 1) xs
-- pattern matching again (see above)
case 1 : 2 : 3 : first_threes of
_ -> []
(x : xs) -> x : take (5 - 1) xs
-- after case analysis (?) we will have
1 : take (5 - 1) (2 : 3 : first_threes)
-- now we return back to our original expression
case 1 : take (5 - 1) (2 : 3 : first_threes) of
[] -> 0
(x : xs) -> x + sum xs
-- after case analysis we will have
1 + sum (take (5 - 1) (2 : 3 : first_threes))
-- (+) operator is strict in both args
-- the first arg is already evaluated, but we also need to evaluate the second
1 + case take (5 - 1) (2 : 3 : first_threes) of
[] -> 0
(x : xs) -> x + sum xs
-- and so on...
-- in the end we will get
1 + (2 + (3 + (1 + (2 + (0)))))
-- which is evaluated in reverse order (starting from the `0`)

Related

how does enumFromTo work in haskell and what optimizations speed up the GHC implementation vs naive implementations

I'm learning haskell, and one of the exercises required that I write a function equivalent to enumFromTo.
I came up with the following two implementations:
eft' :: Enum a => a -> a -> [a]
eft' x y = go x y []
where go a b sequence
| fromEnum b < fromEnum a = sequence
| otherwise = go (succ a) b (sequence ++ [a])
eft :: Enum a => a -> a -> [a]
eft x y = go x y []
where go a b sequence
| fromEnum b < fromEnum a = sequence
| otherwise = go a (pred b) (b : sequence)
I had a hunch that the first version does more work, as it puts each element into a list and concatenates to the existing sequence, while the second version prepends a single element to a list. Is this the main reason for the performance difference or are there other significant factors or is my hunch slightly off the mark?
Testing in ghci with :set +s reveals on my machine (Windows 10, GHC 8.2.2, intel i7-4770HQ):
*Lists> take 10 (eft 1 10000000)
[1,2,3,4,5,6,7,8,9,10]
(9.77 secs, 3,761,292,096 bytes)
*Lists> take 10 (eft' 1 10000000)
[1,2,3,4,5,6,7,8,9,10]
(27.97 secs, 12,928,385,280 bytes)
*Lists> take 10 (enumFromTo 1 10000000)
[1,2,3,4,5,6,7,8,9,10]
(0.00 secs, 1,287,664 bytes)
My second hunch was that the take 10 (eft 1 10000000) should perform better than take 10 (eft' 10000000) because the latter has to build the list up all the way from 10000000 to 10 before it can return any useful values that we take. Clearly this hunch was wrong, and I'm hoping someone can explain why.
Finally, the ghc implementation is incredibly more efficient than my naive implementations. I am curious to understand other optimizations have been applied to speed it up. The answer to this similarly titled SO question shares some code that seems to be from the ghc implementation, but doesn't explain how the "nastiness" gains efficiency.
The problem with eft is that it still requires the entire list to be built, regardless of your attempt to cut it down with take 10. Tail recursion is not your friend when you want to build things lazily. What you want is guarded recursion (i.e. recursive calls right behind the relevant constructor, as in foldr, so that they can be left unevaluated when you don't need them):
eft'' :: Enum a => a -> a -> [a]
eft'' x y
| fromEnum y < fromEnum x = []
| otherwise = x : eft'' (succ x) y
GHCi> take 10 (eft 1 10000000)
[1,2,3,4,5,6,7,8,9,10]
(7.48 secs, 2,160,291,096 bytes)
GHCi> take 10 (eft'' 1 10000000)
[1,2,3,4,5,6,7,8,9,10]
(0.00 secs, 295,752 bytes)
GHCi> take 10 (enumFromTo 1 10000000)
[1,2,3,4,5,6,7,8,9,10]
(0.00 secs, 293,680 bytes)
As for eft' being worse than eft, that indeed has to do with (++). For reference, here are definitions for take and (++) (I'm using the Report definitions rather than the GHC ones, but the slight differences don't actually matter here):
take :: Int -> [a] -> [a]
take n _ | n <= 0 = []
take _ [] = []
take n (x:xs) = x : take (n-1) xs
(++) :: [a] -> [a] -> [a]
[] ++ ys = ys
(x:xs) ++ ys = x : (xs ++ ys)
If you hand-evaluate eft, you get to see how it has to build the entire list before giving you any element:
take 3 (eft 1 5)
take 3 (go 1 5 [])
take 3 (go 1 4 (5 : []))
take 3 (go 1 3 (4 : 5 : []))
-- etc.
take 3 (1 : 2 : 3 : 4 : 5 : [])
1 : take 2 (2 : 3 : 4 : 5 : [])
1 : 2 : take 1 (3 : 4 : 5 : [])
-- etc.
At least, though, once you get past the gos the list is ready for consumption. That is not the case with eft' -- the (++) still have to be dealt with, and doing so is linear with respect to the length of the list:
take 3 (eft' 1 5)
take 3 (go 1 5 [])
take 3 (go 2 5 ([] ++ [1]))
take 3 (go 3 5 (([] ++ [1]) ++ [2]))
-- etc.
take 3 ((((([] ++ [1]) ++ [2]) ++ [3]) ++ [4]) ++ [5])
take 3 (((([1] ++ [2]) ++ [3]) ++ [4]) ++ [5])
take 3 ((((1 : ([] ++ [2])) ++ [3]) ++ [4]) ++ [5])
take 3 ((((1 : [2]) ++ [3]) ++ [4]) ++ [5])
take 3 (((1 : ([2] ++ [3])) ++ [4]) ++ [5])
-- etc.
take 3 (1 : ((([2] ++ [3]) ++ [4]) ++ [5]))
1 : take 2 ((([2] ++ [3]) ++ [4]) ++ [5])
It gets worse: you have to do it again with the remaining tail of the list for every single element!
1 : take 2 ((([2] ++ [3]) ++ [4]) ++ [5])
1 : take 2 (((2 : ([] ++ [3])) ++ [4]) ++ [5])
1 : take 2 (((2 : [3]) ++ [4]) ++ [5])
1 : take 2 ((2 : ([3] ++ [4])) ++ [5])
-- etc.
1 : take 2 (2 : (([3] ++ [4]) ++ [5]))
1 : 2 : take 1 (([3] ++ [4]) ++ [5])
-- etc.
In fact, the take 10 disguises the fact that eft', unlike eft, is quadratic:
GHCi> last $ eft' 1 10000
10000
(1.83 secs, 4,297,217,200 bytes)
GHCi> last $ eft' 1 20000
20000
(7.59 secs, 17,516,804,952 bytes)
GHCi> last $ eft 1 5000000
5000000
(3.81 secs, 1,080,282,784 bytes)
GHCi> last $ eft 1 10000000
10000000
(7.51 secs, 2,160,279,232 bytes)
For the sake of completeness, here is the corresponding hand-evaluation for eft'':
take 3 (eft'' 1 5)
take 3 (1 : eft'' 2 5)
1 : take 2 (eft'' 2 5) -- No need to evaluate `eft'' 2 5` to get the first element.
1 : take 2 (2 : eft'' 3 5)
1 : 2 : take 1 (eft'' 3 5)
-- etc.
1 : 2 : 3 : take 0 (eft'' 4 5) -- No need to go further.
1 : 2 : 3 : []

Add up all items from a list and restart from 0

Is it possible in Haskell to write a function which add up all items from an integer list and if a sum in the middle of the list is under 0, than restart add up with 0. I mean something like this:
[2,5,-6,-2,8,4]
2 + 5 = 7
7 - 6 = 1
1 - 2 = -1 restart here because we are under 0
0 + 8 = 8
8 + 4 = 12
function return 12
Of course I know that I can add up all items from a list with this code:
sum :: [Int] -> Int
sum [x] = x
sum (x:l) = x + sum l
But I do not know how I can restart the function if a sum is under 0. Any ideas for that or is that not possible in an functional coding language because we don't have real variables or something else?
Let me use scanl to show what is going on and then foldl to get only the actual result.
First let us simply try to add all elements of the list:
Prelude> scanl (+) 0 [2,5,-6,-2,8,4]
[0,2,7,1,-1,7,11]
This is equivalent to:
Prelude> scanl (\a b -> a+b) 0 [2,5,-6,-2,8,4]
[0,2,7,1,-1,7,11]
To avoid negative intermediate numbers you can change it like this:
Prelude> scanl (\a b -> max 0 (a+b)) 0 [2,5,-6,-2,8,4]
[0,2,7,1,0,8,12]
To get only the actual result, replace scanl by foldl:
Prelude> foldl (\a b -> max 0 (a+b)) 0 [2,5,-6,-2,8,4]
12
It's very possible, you use an accumulator variable.
sumPos xs = go 0 xs where
go acc [] = acc
go acc (x:xs) = go (max (acc + x) 0) xs
This can be factored by built-in recursion functions like foldl' very nicely.
sumPos = foldl' step 0 where
step x acc = max 0 (x + acc)
Or even foldl' (max 0 .: (+)) 0 if you define (.:) = (.).(.) as some people like to.

Definiton of length using foldr

I'm trying to understand a part in the lecture notes of a class I'm taking. It defines the length function as:
length = foldr (\_ n -> 1 + n) 0
Can someone explain me how this works? I can't wrap my mind around it.
First, type of foldr: (a -> b -> b) -> b -> [a] -> b
Taking the usage into context, foldr takes in 3 arguments: a function (that takes in a. an element of a list and b. an accumulator, and returns the accumulator), the starting value of accumulator, and a list. foldr returns the final result of the accumulator after applying the function through the list.
As for this piece of code:
length = foldr (\_ n -> 1 + n) 0
As you can see, it is missing the list - so the return value of the right hand side is a function that will take in a list and produce an Int (same type as 0). Type: [a] -> Int.
As for what the right hand side means: (\_ n -> 1 + n) 0
\ means declare an unnamed function
_ means ignore the element from the list (correspond to a in the type of foldr). As you know, foldr will go through the list and apply the function to each element. This is the element passed into the function. We don't have any use of it in a length function, so we denote that it should be ignored.
n is the parameter for the Int passed in as accumulator.
-> means return
1 + n will increment the accumulator. You can imagine that the return value is passed back to foldr and foldr saves the value to pass into the next call to the function (\_ n -> 1 + n).
The 0 outside the bracket is the starting value of the counter.
The function foldr is to fold the list with a right associative operator, you can easily understand what the function does if you use the operator(+), (The function has the same behavior as sum):
foldr (+) 0 [1,2,3,4,5] = 1+(2+(3+(4+(5+0))))
For your length function, it is equivalent to:
foldr (\_ n -> 1 + n) 0 [1,2,3,4,5] = 1+(1+(1+(1+(1+0))))
That is what the foldr for
There's several equivalent ways to understand it. First one: foldr f z [1, 2, 3, 4, ..., n] computes the following value:
f 1 (f 2 (f 3 (f 4 (f ... (f n z)))))
So in your case:
length [1,2,3,4] = foldr (\_ n -> 1 + n) 0 [1,2,3,4]
= (\_ n -> 1 + n) 1 ((\_ n -> 1 + n) 2 ((\_ n -> 1 + n) 3 ((\_ n -> 1 + n) 4 0)))
= (\_ n -> 1 + n) 1 ((\_ n -> 1 + n) 2 ((\_ n -> 1 + n) 3 (1 + 0)))
= (\_ n -> 1 + n) 1 ((\_ n -> 1 + n) 2 (1 + (1 + 0)))
= (\_ n -> 1 + n) 1 (1 + (1 + (1 + 0)))
= 1 + (1 + (1 + (1 + 0)))
= 1 + (1 + (1 + 1))
= 1 + (1 + 2)
= 1 + 3
= 4
Another one is to start from this function, which copies a list:
listCopy :: [a] -> [a]
listCopy [] = []
listCopy (x:xs) = x : listCopy xs
That may look like a trivial function, but foldr is basically just that, but except of hardcoding the empty list [] and the pair constructor : into the right hand side, we instead use some arbitrary constant and function supplied as arguments. I sometimes like to call these arguments fakeCons and fakeNil (cons and nil are the names of the : operator and [] constant in the Lisp language), because in a sense you're "copying" the list but using fake constructors:
foldr fakeCons fakeNil [] = fakeNil
foldr fakeCons fakeNil (x:xs) = fakeCons x (subfold xs)
where subfold = foldr fakeCons fakeNil
So under this interpretation, your length function is "copying" a list, except that instead of the empty list it's using 0, and instead of : it's discarding the elements and adding 1 to the running total.
And here's yet a third intepretation of foldr f z xs:
z is the solution of your problem when the list is empty.
f is a function that takes two arguments: an element of the list , and a partial solution: the solution to your problem for the list of elements that appear to the right of the element that's passed to f. f then produces a solution that's "one element bigger."
So in the case of length:
The length of an empty list is 0, so that's why you use 0 as the second argument to foldr.
If the length of xs is n, then the length of x:xs is n+1. That's what your first argument to foldr, \_ n -> n + 1, is doing: it's computing the length of a list, given as arguments the first element of the list (which in this case we ignore) and the length of the rest of the list (n).
This way of thinking about foldr is very powerful, and should not be underestimated. Basically, in the function that you pass as the first argument to foldr, you're allowed to assume that the problem you're trying to solve has already been solved for all lists shorter than the one you're dealing with. All your argument function has to do, then, is to compute an answer for a list that's one element longer.

Haskell: Equation Expander 1+(1+(1+(1+(…))))=∞

Does there exist a equation expander for Haskell?
Something like foldr.com: 1+(1+(1+(1+(…))))=∞
I am new to Haskell I am having trouble understanding why certain equations are more preferable than others. I think it would help if I could see the equations expanded.
For example I found foldr vs foldl difficult to understand at first until I saw them expanded.
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr k z xs = go xs
where
go [] = z
go (y:ys) = y `k` go ys
foldl :: (a -> b -> a) -> a -> [b] -> a
foldl f z0 xs0 = lgo z0 xs0
where
lgo z [] = z
lgo z (x:xs) = lgo (f z x) xs
From the definitions I can see that foldr expands like this:
foldr (+) 0 [1..1000000] -->
1 + (foldr (+) 0 [2..1000000]) -->
1 + (2 + (foldr (+) 0 [3..1000000])) -->
1 + (2 + (3 + (foldr (+) 0 [4..1000000]))) -->
1 + (2 + (3 + (4 + (foldr (+) 0 [5..1000000])))) -->
and foldl expands like this:
foldl (+) 0 [1..1000000] -->
foldl (+) (foldl (+) 0 [1]) [2..1000000]) -->
foldl (+) (foldl (+) (foldl (+) 0 [1])) [3..1000000]) -->
or from Haskell Wiki on foldr fold foldl':
let z1 = 0 + 1
in foldl (+) z1 [2..1000000] -->
let z1 = 0 + 1
z2 = z1 + 2
in foldl (+) z2 [3..1000000] -->
let z1 = 0 + 1
z2 = z1 + 2
z3 = z2 + 3
in foldl (+) z3 [4..1000000] -->
let z1 = 0 + 1
z2 = z1 + 2
z3 = z2 + 3
z4 = z3 + 4
in foldl (+) z4 [5..1000000] -->
However, I have trouble on larger equations understanding why things work the way they do in Haskell. For example the first sieve function uses 1000 filters while the second sieve function takes only 24 to find the 1001 prime.
primes = sieve [2..]
where
sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]
primes = 2: 3: sieve (tail primes) [5,7..]
where
sieve (p:ps) xs = h ++ sieve ps [x | x <- t, rem x p /= 0]
-- or: filter ((/=0).(`rem`p)) t
where (h,~(_:t)) = span (< p*p) xs
Haskell Wiki on Primes
I have spent a good while working out and expanding by hand. I have come to understand how it works. However, an automated tool to expand certain expressions would greatly improve my understanding of Haskell.
In addition I think it could also serve to help questions that seek to optimize Haskell code:
Optimizing Haskell Code
Help optimize my haskell code - Calculate the sum of all the primes below two million
Is there a tool to expand Haskell expressions?
David V. Thank you for those links. Repr is definitely worth adding to my tool box. I would like to add some additional libraries that I found useful.
HackageDB : Trace (As of December 12, 2010)
ghc-events library and program: Library and tool for parsing .eventlog files from GHC
hood library: Debugging by observing in place
hpc-strobe library: Hpc-generated strobes for a running Haskell program
hpc-tracer program: Tracer with AJAX interface
The Hook package seems to be what I am looking for. I will post more samples later today.
Hood
main = runO ex9
ex9 = print $ observe "foldl (+) 0 [1..4]" foldl (+) 0 [1..4]
outputs
10
-- foldl (+) 0 [1..4]
{ \ { \ 0 1 -> 1
, \ 1 2 -> 3
, \ 3 3 -> 6
, \ 6 4 -> 10
} 0 (1 : 2 : 3 : 4 : [])
-> 10
}
I was unaware of the Hackage library (as I am just getting into Haskell). It reminds me of Perl's CPAN. Thank you for providing those links. This is a great resource.
This is in no way a full reply to your question, but I found a conversation on Haskell-Cafe that have some replies :
http://www.haskell.org/pipermail/haskell-cafe/2010-June/078763.html
That thread links to this package :
http://hackage.haskell.org/package/repr that according to the page "allows you to render overloaded expressions to their textual representation"
The example supplied is :
*Repr> let rd = 1.5 + 2 + (3 + (-4) * (5 - pi / sqrt 6)) :: Repr Double
*Repr> show rd
"fromRational (3 % 2) + 2 + (3 + negate 4 * (5 - pi / sqrt 6))"
This is an answer to an unasked question, think of it as a long comment.
(Please downvote only then below 0, iff you think that it does not fit. I'll remove it then.)
As soon as you are a bit more experienced, you might not want to see the way things expand, anymore. You'll want to understand HOW things work, which then supersedes the question WHY it works; you won't gain much just by observing how it expands, anymore.
The way to analyse the code is much simpler than you might think: Just label every parameter/variable either as "evaluated" or "unevaluated" or "to-be-evaluated", depending on the progression of their causal connections.
Two examples:
1.) fibs
The list of all Fibonacci Numbers is
fibs :: (Num a) => [a]
fibs = 1 : 1 : zipWith (+) fibs (tail fibs)
The first two elements are already evaluated; so, label the 3rd element (which has value 2) as to-be-evaluated and all remaining as unevaluated. The 3rd element will then be the (+)-combination of the first elements of fibs and tail fibs, which will be the 1st and 2nd element of fibs, which are already labelled as evaluated. This works with the n-th element to-be-evaluated and the (n-2)-nd and (n-1)-st already evaluated elements respectively.
You can visualize this in different ways, i.e.:
fibs!!(i+0)
+ fibs!!(i+1)
= fibs!!(i+2)
(fibs)
zipWith(+) (tail fibs)
= (drop 2 fibs)
1 : 1 : 2 : 3 ...
(1 :)1 : 2 : 3 : 5 ...
(1 : 1 :)2 : 3 : 5 : 8 ...
2.) Your example "sieve (p:ps) xs"
primes = 2: 3: sieve (tail primes) [5,7..]
where
sieve (p:ps) xs = h ++ sieve ps [x | x <- t, rem x p /= 0]
-- or: filter ((/=0).(`rem`p)) t
where (h,~(_:t)) = span (< p*p) xs
In "sieve (p:ps) xs",
p is evaluated,
ps is unevaluated, and
xs is an evaluated infinite partialy-sieved list (not containing p but containing p²), which you can guess reading the recursion and/or recognizing that the values of h need to be prime.
Sieve should return the list of primes after p, so at least the next prime is to-be-evaluated.
The next prime will be in the list h, which is the list of all (already sieved) numbers k where p < k < p²; h contains only primes because xs does neither contain p nor any number divisible by any prime below p.
t contains all numbers of xs above p². t should be evaluated lazy instead of as soon as possible, because there might not even be the need to evaluate all elements in h. (Only the first element of h is to-be-evaluated.)
The rest of the function definition is the recursion, where the next xs is t with all n*p sieved out.
In the case of foldr, an analysis will show that the "go" is only defined to speed up the runtime, not the readability. Here is an alternative definition, that is easier to analyse:
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr (.:) e (x:xs) = x .: (foldr (.:) e xs)
foldr (.:) e [] = e
I've described its functionality here (without analysis).
To train this type of analysing, you might want to read the sources of some standard libraries; i.e. scanl, scanr, unfoldr in the source of Data.List.

How does foldr work?

Can anybody explain how does foldr work?
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?
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
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.
It helps to understand the distinction between foldr and foldl. Why is foldr called "fold right"?
Initially I thought it was because it consumed elements from right to left. Yet both foldr and foldl consume the list from left to right.
foldl evaluates from left to right (left-associative)
foldr evaluates from right to left (right-associative)
We can make this distinction clear with an example that uses an operator for which associativity matters. We could use a human example, such as the operator, "eats":
foodChain = (human : (shark : (fish : (algae : []))))
foldl step [] foodChain
where step eater food = eater `eats` food -- note that "eater" is the accumulator and "food" is the element
foldl `eats` [] (human : (shark : (fish : (algae : []))))
== foldl eats (human `eats` shark) (fish : (algae : []))
== foldl eats ((human `eats` shark) `eats` fish) (algae : [])
== foldl eats (((human `eats` shark) `eats` fish) `eats` algae) []
== (((human `eats` shark) `eats` fish) `eats` algae)
The semantics of this foldl is: A human eats some shark, and then the same human who has eaten shark then eats some fish, etc. The eater is the accumulator.
Contrast this with:
foldr step [] foodChain
where step food eater = eater `eats` food. -- note that "eater" is the element and "food" is the accumulator
foldr `eats` [] (human : (shark : (fish : (algae : []))))
== foldr eats (human `eats` shark) (fish : (algae : []))))
== foldr eats (human `eats` (shark `eats` (fish)) (algae : [])
== foldr eats (human `eats` (shark `eats` (fish `eats` algae))) []
== (human `eats` (shark `eats` (fish `eats` algae)
The semantics of this foldr is: A human eats a shark which has already eaten a fish, which has already eaten some algae. The food is the accumulator.
Both foldl and foldr "peel off" eaters from left to right, so that's not the reason we refer to foldl as "left fold". Instead, the order of evaluation matters.
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 means fold from the right, so foldr (-) 0 [1, 2, 3] produces (1 - (2 - (3 - 0))). In comparison foldl produces (((0 - 1) - 2) - 3).
When the operators are not commutative foldl and foldr will get different results.
In your case, the first example expands to (10 - (11 - 54)) which gives 53.
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.
I've always thought http://foldr.com to be a fun illustration. See the Lambda the Ultimate post.
Careful readings of -- and comparisons between -- the other answers provided here should already make this clear, but it's worth noting that the accepted answer might be a bit misleading to beginners. As other commenters have noted, the computation foldr performs in Haskell does not "begin at the right hand end of the list"; otherwise, foldr could never work on infinite lists (which it does in Haskell, under the right conditions).
The source code for Haskell's foldr function should make this clear:
foldr k z = go
where
go [] = z
go (y:ys) = y `k` go ys
Each recursive computation combines the left-most atomic list item with a recursive computation over the tail of the list, viz:
a\[1\] `f` (a[2] `f` (a[3] `f` ... (a[n-1] `f` a[n]) ...))
where a[n] is the initial accumulator.
Because reduction is done "lazily in Haskell," it actually begins at the left. This is what we mean by "lazy evaluation," and it's famously a distinguishing feature of Haskell. And it's important in understanding the operation of Haskell's foldr; because, in fact, foldr builds up and reduces computations recursively from the left, binary operators that can short-circuit have an opportunity to, allowing infinite lists to be reduced by foldr under appropriate circumstances.
It will lead to far less confusion to beginners to say rather that the r ("right") and l ("left") in foldr and foldl refer to right associativity and left associativity and either leave it at that, or try and explain the implications of Haskell's lazy evaluation mechanism.
To work through your examples, following the foldr source code, we build up the following expression:
Prelude> foldr (-) 54 [10, 11]
->
10 - [11 - 54] = 53
And again:
foldr (\x y -> (x + y) / 2) 54 [12, 4, 10, 6]
->
(12 + (4 + (10 + (6 + 54) / 2) / 2) / 2) / 2 = 12
I think that implementing map, foldl and foldr in a simple fashion helps explain how they work. Worked examples also aid in our understanding.
myMap f [] = []
myMap f (x:xs) = f x : myMap f xs
myFoldL f i [] = i
myFoldL f i (x:xs) = myFoldL f (f i x) xs
> tail [1,2,3,4] ==> [2,3,4]
> last [1,2,3,4] ==> 4
> head [1,2,3,4] ==> 1
> init [1,2,3,4] ==> [1,2,3]
-- where f is a function,
-- acc is an accumulator which is given initially
-- l is a list.
--
myFoldR' f acc [] = acc
myFoldR' f acc l = myFoldR' f (f acc (last l)) (init l)
myFoldR f z [] = z
myFoldR f z (x:xs) = f x (myFoldR f z xs)
> map (\x -> x/2) [12,4,10,6] ==> [6.0,2.0,5.0,3.0]
> myMap (\x -> x/2) [12,4,10,6] ==> [6.0,2.0,5.0,3.0]
> foldl (\x y -> (x+y)/2) 54 [12, 4, 10, 6] ==> 10.125
> myFoldL (\x y -> (x+y)/2) 54 [12, 4, 10, 6] ==> 10.125
foldl from above: Starting accumulator = 54
(12 + 54) / 2 = 33
(4 + 33) / 2 = 18.5
(10 + 18.5) / 2 = 14.25
(6 + 14.25) / 2 = 10.125`
> foldr (++) "5" ["1", "2", "3", "4"] ==> "12345"
> foldl (++) "5" ["1", "2", "3", "4"] ==> “51234"
> foldr (\x y -> (x+y)/2) 54 [12,4,10,6] ==> 12
> myFoldR' (\x y -> (x+y)/2) 54 [12,4,10,6] ==> 12
> myFoldR (\x y -> (x+y)/2) 54 [12,4,10,6] ==> 12
foldr from above: Starting accumulator = 54
(6 + 54) / 2 = 30
(10 + 30) / 2 = 20
(4 + 20) / 2 = 12
(12 + 12) / 2 = 12
Ok, lets look at the arguments:
a function (that takes a list element and a value (a possible partial result) of the same kind of the value it returns);
a specification of the initial result for the empty list special case
a list;
return value:
some final result
It first applies the function to the last element in the list and the empty list result. It then reapplies the function with this result and the previous element, and so forth until it takes some current result and the first element of the list to return the final result.
Fold "folds" a list around an initial result using a function that takes an element and some previous folding result. It repeats this for each element. So, foldr does this starting at the end off the list, or the right side of it.
folr f emptyresult [1,2,3,4] turns into
f(1, f(2, f(3, f(4, emptyresult) ) ) ) . Now just follow parenthesis in evaluation and that's it.
One important thing to notice is that the supplied function f must handle its own return value as its second argument which implies both must have the same type.
Source: my post where I look at it from an imperative uncurried javascript perspective if you think it might help.
The images in this wiki page visualize the idea of foldr (and foldl also):
https://en.wikipedia.org/wiki/Fold_%28higher-order_function%29
For example, the result of foldr (-) 0 [1,2,3] is 2. It can be visualized as:
-
/ \
1 -
/ \
2 -
/ \
3 0
That is (from bottom to the top):
1 - ( -1 ) = 2
2 - ( 3 )
3 - 0
So foldr (\x y -> (x+y)/2) 54 [12, 4, 10, 6] is being computed through:
12 `f` (12.0) = 12.0
4 `f` (20.0)
10 `f` (30.0)
6 `f` 54

Resources