Why does (.) map have this type?

  • A+

I tried to find the type of the function (.) map but somehow find that it is ((a -> d) -> (a -> e)) -> ([d] -> [e]) which according to GHCI is not correct because it should be (.) map :: (a1 -> a2 -> b) -> a1 -> [a2] -> [b].

What am I doing wrong?


Deriving the type...

We have as ingredients:

(.) :: (b -> c) -> (a -> b) -> a -> c map :: (d -> e) -> [d] -> [e] 

(here I used different type identifiers for the two functions to avoid any confusion). A more verbose form (where we make it more explicit that every function takes exactly one parameter) is:

(.) :: (b -> c) -> ((a -> b) -> (a -> c)) map :: (d -> e) -> ([d] -> [e]) 

Since map is the first parameter of (.) that means that its type (d -> e) -> ([d] -> [e]) should match the input type of the (.) function (so b -> c). This thus means:

  b        -> c ~ (d -> e) -> ([d] -> [e]) ------------------------------ b ~ (d -> e), c ~ ([d] -> [e]) 

So that means that the result type of (.) map is:

(a -> b) -> (a -> c) 

which is equivalent to:

(a -> (d -> e)) -> (a -> ([d] -> [e])) 

or less verbose:

(.) map :: (a -> d -> e) -> a -> [d] -> [e] 

... and its implementation

The (.) function can be seen as (.) f g == /x -> f (g x). So that means that our function

h = (.) map 

is equivalent to:

h f x = map (f x) 

It thus takes as input a function f and an object x, and than performs a map with f x as function.

Semancially you could say that we make a "map where one has to inject a 'contect'-objecct" of type a. This context is then taken into account by the processor. This could be useful if we want to apply multiple maps, each with a small change, and thus first pass a "context-object". This is of course an interpretation of humans. For a compiler, the x can have any use, interpretation, etc.


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: