0

I'm trying to understand the type of the expression (map . map). Since the type of (.) is (b -> c) -> (a -> b) -> a -> c I don't understand how this works with the map function, because map takes two arguments which doesn't fit with the functions (b -> c) and (a -> b).

  • 8
    Mind that `a -> b -> c` is short for `a -> (b -> c)`. In Haskell, all functions only take *one* argument. – Willem Van Onsem Aug 17 '17 at 12:15
  • 2
    I was thinking about that. But I couldn't decide wether it should be split up as `a -> (b -> c)` or `(a -> b) -> c`. But what you say makes sense to me now. Am I correct then if I think about it this way: if we want to consider map as a "one-parameter-function" its type is `(a -> b) -> ([a] -> [b])`, since if we supply it with its first parameter (the `(a -> b)` function) what we get in return is a function of type `([a] -> [b])`. So the types `(a -> b)` and `([a] -> [b])` correspond to the `a` and `b` in `(a -> b)` in the type for `(map . map)`? – Nicrophorus Aug 17 '17 at 13:13
  • 3
    `a -> b -> c` is the same as `a -> (b -> c)` but different that `(a -> b) -> c` – RamiroPastor Aug 17 '17 at 13:20
  • Related question: https://stackoverflow.com/questions/23030638/how-fmap-fmap-typechecks – Sibi Aug 17 '17 at 13:21

2 Answers2

5

Quoting GHCI:

Prelude> :t map.map
map.map :: (a -> b) -> [[a]] -> [[b]]

But for map itself, type is

map :: (a -> b) -> [a] -> [b]

which you can see as

map :: (a -> b) -> ([a] -> [b])

So, if we have that (.) :: (t2 -> t3) -> (t1 -> t2) -> t1 -> t3

Then:

  • type t1 is (a -> b)
  • type t2 is ([a] -> [b])
  • type t3 is ([[a]] -> [[b]])
RamiroPastor
  • 1,085
  • 1
  • 7
  • 18
1

One way I like to think of it is that map turns an a -> b into an [a] -> [b], so map . map does it twice. The first map turns your a -> b into an [a] -> [b], and the second map repeats the process, turning it into an [[a]] -> [[b]].

"Applying map to an a -> b turns it into an [a] -> [b]", so, it seems pretty pretty logical that applying map to an [a] -> [b] would turn it into an [[a]] -> [[b]]. You're just applying map to a function twice.

Incidentally:

-- apply map to a function once
            map :: (a -> b) -> (  [a]   ->   [b]  )
-- apply map to a function twice
      map . map :: (a -> b) -> ( [[a]]  ->  [[b]] )
-- apply map to a function three times
map . map . map :: (a -> b) -> ([[[a]]] -> [[[b]]])
Justin L.
  • 13,510
  • 5
  • 48
  • 83