Because a -> b -> b
is actually a -> (b -> b)
.
Since id :: a -> a
, this unifies a
with b -> b
and so we get, with type variables consistently renamed for uniqueness,
foldr :: (a -> (b -> b)) -> b -> [ a ] -> b
id :: c -> c
----------------------------------------------- |- a ~ c , c ~ b -> b
foldr id :: b -> [ c ] -> b
foldr id :: b -> [b -> b] -> b
That's all.
So what does it do?
foldr f z [x, y, ..., n] = f x (f y (... (f n z)...))
= x `f` y `f` ... n `f` z -- infixr _ `f`
foldr id z [x, y, ..., n] =
= id x (id y ( ... (id n z )...))
= x ( y ( ... ( n ( id z))...))
= ( x . y . ... . n . id ) z
= foldr (.) id [x,y,...,n] z
Thus foldr id = foldr ($) = flip (foldr (.) id)
which is quite nice to have. The functions held in the list all stack up, because the output and input types match.