Search code examples
haskellfunctor

confused about function as instance of Functor in haskell


The type of fmap in Functor is:

fmap :: Functor f => (a -> b) -> f a -> f b

it looks like ,first apply function (a -> b) to the parameter of f a to create a result of type b, then apply f to it, and result is f b

using Maybe a for example:

 fmap show (Just 1)
 result is : Just "1"

same as saying:

Just (show 1)

but when (->) is used as a Functor (in Control.Monad.Instances)

import Control.Monad.Instances
(fmap show Just) 1
result is : "Just 1"

that is, Just is applied first, then show is applied. In another example ,result is same:

 fmap (*3) (+100) 1
 result is 303

why not *3 first, then +100?


Solution

  • the type of fmap in Functor is:

    fmap :: Functor f => (a -> b) -> f a -> f b
    

    it looks like ,first apply function (a -> b) to the parameter of f a to create a result of type b, then apply f to it, and result is f b

    That is the type of fmap, but your interpretation of what that type means is wrong.

    You seem to assume that f a has one parameter, and that that parameter has type a.

    Consider xs :: [a]:

    • Perhaps xs = [].
    • Perhaps xs = [x1].
    • Perhaps xs = [x1, x2].
    • ...

    The type f a is a functor f with a single type parameter a. But values of type f a do not necessarily take the form F x, as you can see from the first and third cases above.

    Now consider fmap f xs:

    • Perhaps fmap f xs = [].
    • Perhaps fmap f xs = [f x1].
    • Perhaps fmap f xs = [f x1, f x2].
    • ...

    We don't necessarily apply f at all (first case)! Or we might apply it more than once (third case).

    What we do is replace the things of type a, with things of type b. But we leave the larger structure intact --- no new elements added, no elements removed, their order is left unchanged.


    Now let's think about the functor (c ->). (Remember, a functor takes one type parameter only, so the input to (->) is fixed.)

    Does a c -> a even contain an a? It might not contain any as at all, but it can somehow magic one out of thin air when we give it a c. But the result from fmap has type c -> b: we only have to provide a b out of that when we're presented with a c.

    So we can say fmap f x = \y -> f (x y).

    In this case, we're applying f on demand --- every time the function we return gets applied, f gets applied as well.