Reputation: 5709
I am currently reading about the identity Monad and one piece defines fmap as this:
fmap :: (a -> b) -> (W a -> W b)
fmap f (W x) = W (f x)
The text says the goal is creating a function which changes an existing function for the types of a and b to another function which applies the original function to the types W a and W b.
From this point of view there are two functions involved and the type signature also looks like this: Its parameter is one function and it delivers a function.
What puzzled me at first is that the actual type of fmap as ghci tells is:
fmap :: (a -> b) -> W a -> W b
Thinking about that reveals that the function fmap gets a function and a parameter of type W a and then applies the function on the a in the W a and returns the result as W b. Which happens to be the description of what the code for fmap does.
I am pretty sure that it does not make any difference in what the function does if one omits the parenthesis in the type definition.
Am I right that this is similar to as if I would say:
addab
is a function which creates a function that can add a value to its parameter
And give this example code:
addab :: Int -> (Int -> Int)
addab x y = x + y
add1 :: Int -> Int
add1 = addab 1
Basically just indicating that the function is made to be used without giving all the parameters to it?
Or is there any deeper meaning to it which I did not consider?
Upvotes: 3
Views: 173
Reputation: 120711
Well, for starters it can't make a difference because ->
is right-associative, meaning (a->b)->c->d
is defined as (a->b) -> (c->d)
!
As to why and so on, you're exactly right: it's just currying. The particular reason why that is so popular in Haskell is that partial application lends itself very well to writing computation pipelines in a natural way: stuff like unzip . fmap f . reverse
. Here, the fmap
doesn't really receive its list argument, only the morphism it's supposed to lift onto lists. The result morphism has a type ([a]->[b])
.
This (a->b) -> (F a->F d)
is actually the more "fundamental" definition: mathematicians define a functor as mapping morphisms to morphisms; the "function and argument" writing (a->b, F a) -> F b
generally doesn't make any sense because there is, in general categories, no meaningful wway to combine morphisms with objects. Only, as nomen sais, in cartesian closed categories morphisms are objects as well.
Upvotes: 5
Reputation: 3715
Both of those types for fmap
are correct. They are effectively equivalent.
And your experiment is correct as well.
What is going on here is that the space of functions is a closed cartesian category. In particular, this means that we can do partial function application. It is deep, insofar as there are logics/languages where partial function application is invalid as a rule of inference. Of course, this means that Haskell has more valid ways to factor a program than other languages.
For example, your addab
function and a multab
function you can define yourself let us do things like:
addab 1 . addab 2 . multab 3 $ 5
Upvotes: 4