How does composing with id change type

function-composition, haskell

Solution

This is not composition with `id`, as you'd get from `foldr . id` (notice the absence of parens). That would indeed be equivalent to `foldr` alone, perhaps the most important equivalency in category theory and thus also fundamental to Haskell.

Instead, what you've done there is, passed both `(.)` and `id` as arguments to `foldr`: putting `.` in parens makes it just another expression so ordinary Haskell function parsing applies, i.e. greedily use consecutive terms as arguments to the first one. You're lucky that this makes for a good type at all, for instance `succ (.) id` would have given the ridiculous signature `Enum ((c -> c) -> (a -> c) -> a -> c) => (a -> c) -> a -> c`.

How exactly it works with `foldr` can be seen by writing

 (.) :: (y->z) -> (x->y) -> (x->z)

unify `(x->y) = (x->z)` as in `foldr`'s argument, i.e. `y = z`,

 (.) :: (y->y) -> (x->y) -> (x->y)

 foldr (.) :: (x->y) -> [y->y] -> (x->y)

Then `id` also requires `x = y`,

 foldr (.) id :: [x->x] -> (x->x)

Problem

If the type of `foldr` is ``` > :t foldr forall a b. (a -> b -> b) -> b -> [a] -> b ``` and ``` > :t id forall a. a -> a ``` then I would expect `foldr (.) id` to have the same type as `foldr`, rather than ``` > :t foldr (.) id forall b. [b -> b] -> b -> b ``` It appears I'm mistaken about how composition works, because I had thought that for a function `f` that `f . id` would give `f(id(x)) == f(x)`, preserving the type of `f`. What am I misunderstanding that would clarify the meaning of `foldr (.) id` and composition more generally?

Original source