Aaron Denney wnoise at ofb.net
Tue Sep 25 06:36:09 EDT 2007

```On 2007-09-25, Andrew Coppin <andrewcoppin at btinternet.com> wrote:
> Aaron Denney wrote:
>> On 2007-09-25, Andrew Coppin <andrewcoppin at btinternet.com> wrote:
>>
>>> BTW, one *extremely* common function that I've never seen mentioned
>>> anywhere is this one:
>>>
>>>   map2 :: (a -> b) -> [[a]] -> [[b]]
>>>   map2 f = map (map f)
>>>
>>
>> Because someone would have to think of a name for it, when (map . map)
>> is likely to be clearer.
>>
>
> 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.

--
Aaron Denney
-><-

```