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).
Asked
Active
Viewed 871 times
0
Nicrophorus
- 55
- 4
-
8Mind 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
-
2I 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 Answers
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
t1is(a -> b) - type
t2is([a] -> [b]) - type
t3is([[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