Functors
The Functor type class provides an fmap function for types which
implement it. fmap is like a generalised form of map for lists.
class Functor f where
fmap :: (a -> b) -> f a -> f b
The Functor instance for Maybe is
instance Functor Maybe where
fmap f Nothing = Nothing
fmap f (Just x) = Just (f x)
Laws
The functor type class has three laws. Laws are rules that implementing types should follow but are not enforced by the compiler.
-
The mapping must be structure preserving. This means the output should be the same "shape" as the input.
-
Identity law -
fmap id == id. -
Distributivity over
(.)-fmap (a . b) == fmap a . fmap b.
Environment functor
(->) is the type level operator. It can be partially applied.
((->) Int) represents all functions which take one argument of type
Int. This has kind * -> * so can have a Functor instance.
The functor instance for ((->) e) is called the environment functor.
It represents values that exist with respect to some input environment
of type e.
instance Functor ((->) e) where
fmap :: (a -> b) -> (e -> a) -> (e -> b)
fmap f func = \x -> f (func x)
-- or equivalently
fmap = (.)
Control and data functors
Functors can be split into two groups: control and data functors. Data
functors are those which store values, such as [] or Maybe. Control
functors are used for control flow. An example is the environment
functor.
Applicative functors
Applicative functors are a subclass of functors which have the ability
to lift values in. This basically mean take a value and put it in a
functor without using the constructor. It defines two new functions,
pure and (<*>). The first takes a value and lifts it into a functor,
the second is the apply function, which applies a lifted function to a
lifted value.
class Functor f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
The applicative functor instance for Maybe is as follows:
instance Applicative Maybe where
pure x = Just x
Just f <*> Just x = Just (f x)
_ <*> _ = Nothing
Function application function comparison
Functions, functors and applicative functors all have function
application functions. Note that <$> is the same as fmap.
($) :: (a -> b) -> a -> b
(<$>) :: Functor f => (a -> b) -> f a -> f b
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
All three are fairly similar, they take a function in some form, a value
in some form and apply the function to the value giving a result in some
form. The difference between ($) and (<$>) is that the input and
output are wrapped in a functor and then the difference between (<$>)
and (<*>) is the function is also wrapped in the functor.