4

In Haskell, I don’t understand why the partial application foldr id typechecks.

Relevant types are

> :t foldr id
foldr id :: a -> [a -> a] -> a

> :t foldr
foldr :: (a -> b -> b) -> b -> [a] -> b

> :t id
id :: a -> a

The first argument of foldr is (a->b->b). In contrast the type of id is a->a. They shouldn’t be compatible.

Will Ness
  • 70,110
  • 9
  • 98
  • 181
Kin Pu
  • 400
  • 1
  • 4
  • 13

1 Answers1

11

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.

Will Ness
  • 70,110
  • 9
  • 98
  • 181