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
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
:
foldr
.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.