0

I have two simple examples:

1) xt function (what is this?)

Prelude> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
Prelude> :{
Prelude| f::Int->Int
Prelude| f x = x
Prelude| :}
Prelude> xt = fmap f // ?
Prelude> :t xt
xt :: Functor f => f Int -> f Int
Prelude> xt (+2) 1
3

2) xq function (via composition)

Prelude> :{
Prelude| return x = [x]
Prelude| :}
Prelude> xq = return . f
Prelude> :t xq
xq :: Int -> [Int]
Prelude> :t return
return :: a -> [a]

xq function I get through composition return(f(x)). But what does that mean: fmap f and what is difference?

  • Possible duplicate of [In Functional Programming, what is a functor?](https://stackoverflow.com/questions/2030863/in-functional-programming-what-is-a-functor) – chepner Jan 11 '18 at 18:40
  • @chepner My question was not, what a `functor` is. I would like to know what does the notation `fmap f` mean –  Jan 14 '18 at 23:53
  • If you knew what a functor was, it would be obvious what `fmap f` means. It's not special syntax, it's just function application. – chepner Jan 15 '18 at 00:07

2 Answers2

5

The Functor instance for (->) r defines fmap to be function composition:

fmap f g = f . g

Thus, xt (+2) == fmap f (+2) == f . (+2) == (+2) (since f is the identity function for Int). Applied to 1, you get the observed answer 3.


fmap is the function defined by the Functor type class:

class Functor f where
    fmap :: (a -> b) -> f a -> f b

It takes a function as its argument and returns a new function "lifted" into the functor in question. The exact definition is supplied by the Functor instance. Above is the definition for the function functor; here for reference are some simpler ones for lists and Maybe:

instance Functor [] where
    fmap = map

instance Functor Maybe where
    fmap f Nothing = Nothing
    fmap f (Just x) = Just (f x)

> fmap (+1) [1,2,3]
[2,3,4]
> fmap (+1) Nothing
Nothing
> fmap (+1) (Just 3)
Just 4

Since you can think of functors as boxes containing one or more values, the intuition for the function functor is that a function is a box containing the result of applying the function to its argument. That is, (+2) is a box that contains some value plus 2. (F)mapping a function on that box provides a box that contains the result of applying f to the result of the original function, i.e, produces a function that is the composition of f with the original function.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • Thanks, but what does the following syntax mean `fmap f`? That is not a product of two functions. Is it? –  Jan 11 '18 at 17:51
  • `fmap f` is `fmap` applied to `f`, which results in a function. Just like `negate 3` is `negate` applied to `3`, which results in a number – Mor A. Jan 11 '18 at 18:05
  • "`fmap` takes a function as its argument and returns a new function "lifted" into the functor in question". `xt = fmap f` therefore `xt :: Functor f => f Int -> f Int`, but why can not I write `fmap . f`, what is problem here? `return . f` composition works and I get no error. `fmap. fmap` too... –  Jan 11 '18 at 18:32
  • `fmap` *takes* a function as an argument; it is not applied to the return value of the function. Consider `map` (which is `fmap` for lists): `map (+1) [1,2,3]` does not apply `(+1)` to the list, then pass the result to `map`; instead, `map` takes (+1)` as an argument and returns a *new* function which takes a list as its input. – chepner Jan 11 '18 at 18:39
  • @garychaudhry `\f -> fmap . f :: Functor f => (c -> a -> b) -> c -> f a -> f b`, so for `fmap . f` to make sense, `f` should have type `f :: c -> a -> b`. For example, `fmap . (*)` works - because `(fmap . (*)) 3 = fmap ((*) 3) = fmap (3*)`. We can find types of expressions at GHCi prompt with `:t` command, like `Prelude> :t fmap . (*)`. – Will Ness Jan 12 '18 at 09:15
1

Both xq = return . f and xt = fmap f can be eta-expanded:

xq x = (return . f) x = return (f x) = return x

Now it can be eta-contracted:

xq = return

The second is

xt y = fmap f y = fmap (\x -> x) y = fmap id y = id y = y

fmap has type :: Functor f => (a -> b) -> f a -> f b so fmap f has type :: Functor f => f Int -> f Int, because f :: Int -> Int. From its type we see that fmap f is a function, expecting an Int, and producing an Int.

Since f x = x for Ints by definition, it means that f = id for Ints, where id is a predefined function defined just the same way as f is (but in general, for any type).

Then by Functor laws (and that's all we need to know about "Functors" here), fmap id = id and so xt y = y, in other words it's also id - but only for Ints,

xt = id :: Int -> Int

Naturally, xt (+2) = id (+2) = (+2).


Addendum: for something to be a "Functor" means that it can be substituted for f in

fmap id (x :: f a) = x
(fmap g . fmap h)  = fmap (g . h)

so that the expressions involved make sense (i.e. are well formed, i.e. have a type), and the above equations hold (they are in fact the two "Functor laws").

Will Ness
  • 70,110
  • 9
  • 98
  • 181