Functors by example

Running :i Functor in ghci yields the following:

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

It also lists available instances of the Functor type class:

instance Functor (Either a) -- Defined in ‘Data.Either’
instance Functor [] -- Defined in ‘GHC.Base’
instance Functor Maybe -- Defined in ‘GHC.Base’
instance Functor IO -- Defined in ‘GHC.Base’
instance Functor ((->) r) -- Defined in ‘GHC.Base’
instance Functor ((,) a) -- Defined in ‘GHC.Base’

Concrete type signatures

To understand similarities and differences between various instances of the Functor type class we will take a look at the type signatures of the fmap and <$ functions for List, Maybe and Either types:

-- Generic
fmap :: (a -> b) -> f a -> f b

-- List
fmap :: (a -> b) -> [a] -> [b]

-- Maybe
fmap :: (a -> b) -> Maybe a -> Maybe b

-- Either
fmap :: (b -> c) -> Either a b -> Either a c
-- Generic
(<$) :: a -> f b -> f a

-- List
(<$) :: c -> [a] -> [c]

-- Maybe
(<$) :: c -> Maybe a -> Maybe c

-- Either
(<$) :: c -> Either a b -> Either a c

Using fmap with different types

In order to use fmap we need to define a function we want to work with. After it is defined we will apply the function to some instances of the Functor type class:

addOne :: Num a => a -> a
addOne a = a + 1
-- List
fmap addOne [ ]       == [ ]
fmap addOne [1]       == [2]
fmap addOne [1, 2, 3] == [2, 3, 4]
-- Maybe
fmap addOne (Nothing) == Nothing
fmap addOne (Just 2)  == Just 3
-- Either
fmap addOne (Left  0) == Left  0
fmap addOne (Right 2) == Right 3

Interactive Examples:


Using <$ with different types

<$ swaps values in the instance of the Functor typeclass and is originally defined as fmap . const.

-- List
1 <$ [ ]     == [ ]
1 <$ [2]     == [1]
1 <$ [1,2,3] == [1,1,1]
-- Maybe
1 <$ (Nothing) == Nothing
1 <$ (Just 2)  == Just 1
-- Either
1 <$ (Left  0) == Left  0
1 <$ (Right 2) == Right 1

Interactive Examples:


It's not as bad as it looks, or is it? Let me know on twitter - @maciejsmolinski.

In the next post you will learn in a similar way about Applicatives.