Haskell: Functor
Coming from the world of category theory, a functor is a mapping between two categories:
-
in the world of Haskell, usually you can think of it as a type constructor with some special properties. It takes an object and it wraps it.
-
Functors are the building blocks of most
typeclassesin Haskell- If that sounds like a bold claim, Have a look here to convince yourself
-
Functors are (by definition) the pipes between categories - you might be using them already without realising
Use case
We use Functors all the time - it is hard to think of a case where you wouldn’t use it.
The Identity Functor
Let’s create the simplest functor possible
data Identity a = Identity a deriving (Eq, Ord, Show)
instance Functor Identity where
fmap f (Identity m) = Identity $ f m
-
TL;DR What does it do?
- Transforms whatever you give to it into the
Identitytype.
- Transforms whatever you give to it into the
-
What does it need to implement to be a Functor?
fmapaka<$>with the type signature(a -> b) -> f a -> f b. It is pretty intuitive this one takes a function froma -> band transforms the functorf ainto a functorf b. Easy.
-
What laws does it need to satisfy?
-
it must preserve the identity morphism
fmap Id = Id
-
it also must preserve composition of morphisms
fmap (f . g) = fmap f . fmap g
-
- A few examples using our Identity functor:
fmap (+3) $ Identity 3 -- 6
(*2) <$> $ Identity 4 -- 8
- Other functor functions:
<$ :: a -> f a -> f b
-
It’s half the fmap to the left (if that makes sense?). You give it an element and then you give it a functor, and it returns the element wrapped in the functor (a bit like it pushes the element out of the functor and replaces it with what is on the left).
-
an example:
5 <$ Identity 6 -- Identity 5
- That is quite neat. You can even use it with higher types for example:
(+1) <$ Identity 5 -- of the type :: Num a => Identity (a -> a)
Do you see what happened? We now have a higher order Identity type - a
function wrapped in Identity. But what can we do with it? Well we can apply
it - with fmap again.
fmap ($5) ((+1) <$ Identity 3) -- Identity 6
-
We basically flipped the roles of the function and application. And of course
($5) :: (a -> b) -> bis a function that takes a function and it applies to5. -
Also, if you
import Data.Functoryou get$>(which is as you guessed the opposite of<$) andvoidwhich is:: f a -> f (). Pretty straight forward.
In the end
That was it for today. I will try and make an article on each typeclass of
Haskell as I am quite enjoying writing these. The next one will probably be on
Applicative Functors, which you probably know where it leads to.
More reading
These are all very basic applications and simple examples. But if you are curious here is some further reading: