Andrew Coppin andrewcoppin at btinternet.com
Tue Sep 25 06:40:50 EDT 2007

```Aaron Denney wrote:
> On 2007-09-25, Andrew Coppin <andrewcoppin at btinternet.com> wrote:
>
>> OK, *now* I'm puzzled... Why does map . map type-check?
>>
>
> (map . map) = (.) map map
>
> (.) :: (a -> b) -> (b -> c) -> a -> c
>     = (a -> b) -> (b -> c) -> (a -> c)
>
> The first two arguments of (.) are 1-argument functions.
>
> map :: (d -> e) -> [d] -> [e]
>     =  (d -> e) -> ([d] -> [e])
>
> map is either a two argument function _or_ a function that takes one
> argument (a function) and returns a function.
>
> In this latter view, for the first argument, of (.), we need:
>
> a = d -> e
> b = [d] -> [e]
>
> And for the second we know
> b = [d] -> [e]
> so
> c = [[d]] -> [[e]]
>
> for everything to be consistent.
>
> It's much clearer when you think of map not as "running this function
> over this list", but rather "turning this function that operates on
> elements into a function that operates on lists".  Doing that twice (by
> composing) turns a function that operates on elements into a function
> that operates on lists of lists.
>

I just found it rather surprising. Every time *I* try to compose with
functions of more than 1 argument, the type checker complains.
Specifically, suppose you have

foo = f3 . f2 . f1

Assuming those are all 1-argument functions, it works great. But if f1
is a *two* argument function (like map is), the type checker refuses to
allow it, and I have to rewrite it as

foo x y = f3 \$ f2 \$ f1 x y

which is really extremely annoying...

I'm just curiose as to why the type checker won't let *me* do it, but it
will let *you* do it. (Maybe it hates me?)

```