I have issues with the following passage from Learn You A Haskell (Great book imo, not dissing it):
One big difference is that right folds work on i
Remember in Haskell you can use infinite lists because of lazy evaluation. So, head [1..] is just 1, and head $ map (+1) [1..] is 2, even though `[1..] is infinitely long. If you dont get that, stop and play with it for a while. If you do get that, read on...
I think part of your confusion is that the foldl and foldr always start at one side or the other, hence you dont need to give a length.
foldr has a very simple definition
foldr _ z [] = z
foldr f z (x:xs) = f x $ foldr f z xs
why might this terminate on infinite lists, well try
dumbFunc :: a -> b -> String
dumbFunc _ _ = "always returns the same string"
testFold = foldr dumbFunc 0 [1..]
here we pass into foldr a "" (since the value doesn't matter) and the infinite list of natural numbers. Does this terminate? Yes.
The reason it terminates is because Haskell's evaluation is equivalent to lazy term rewriting.
So
testFold = foldr dumbFunc "" [1..]
becomes (to allow pattern matching)
testFold = foldr dumbFunc "" (1:[2..])
which is the same as (from our definition of fold)
testFold = dumbFunc 1 $ foldr dumbFunc "" [2..]
now by the definition of dumbFunc we can conclude
testFold = "always returns the same string"
This is more interesting when we have functions that do something, but are sometimes lazy. For example
foldr (||) False
is used to find if a list contains any True elements. We can use this to define the higher order functionn any which returns True if and only if the passed in function is true for some element of the list
any :: (a -> Bool) -> [a] -> Bool
any f = (foldr (||) False) . (map f)
The nice thing about lazy evaluation, is that this will stop when it encounters the first element e such that f e == True
On the other hand, this isn't true of foldl. Why? Well a really simple foldl looks like
foldl f z [] = z
foldl f z (x:xs) = foldl f (f z x) xs
Now, what would have happened if we tried our example above
testFold' = foldl dumbFunc "" [1..]
testFold' = foldl dumbFunc "" (1:[2..])
this now becomes:
testFold' = foldl dumbFunc (dumbFunc "" 1) [2..]
so
testFold' = foldl dumbFunc (dumbFunc (dumbFunc "" 1) 2) [3..]
testFold' = foldl dumbFunc (dumbFunc (dumbFunc (dumbFunc "" 1) 2) 3) [4..]
testFold' = foldl dumbFunc (dumbFunc (dumbFunc (dumbFunc (dumbFunc "" 1) 2) 3) 4) [5..]
and so on and so on. We can never get anywhere, because Haskell always evaluates the outermost function first (that is lazy evaluation in a nutshell).
One cool consequence of this is that you can implement foldl out of foldr but not vice versa. This means that in some profound way foldr is the most fundamental of all the higher order string functions, since it is the one we use to implement almost all the others. You still might want to use a foldl sometimes, because you can implement foldl tail recursively, and get some performance gain from that.