fmap (+1) (Just 1) == Just 2
Some applicative style examples
I’m not going to define what an applicative functor is, (See
references), but I would like to share some applicative style
examples. After reading a bit about applicative functors I’ve coined
the definition:
functors that can be applied, meaning functors containing functions
fmap
on steroids ?
First step to use applicative functor style is to understand fmap
and the infix notation <$>
. When I try to apply a function to a
value wrapped in a Functor
normally I use fmap
:
But there’s the applicative style
which uses the <$>
symbol. The
<$>
symbol is just the fmap
function, nothing else. The only
difference is that you can use this symbol infix
. That means the
following would work the same:
(+1) <$> (Just 1) == Just 2
And there is another feature, <$>
is left associative, that means
among other things, you can avoid wrapping the right operand in
parenthesis.
The magical <*>
But what if I wanted to do operations over wrapped values. And most of
the time I use the do
notation:
sumMaybe :: (Num a) => Maybe a -> Maybe a -> Maybe a
sumMaybe b c = do
x <- b
y <- c
return (x + y)
This function means that for any applicative functor it would take the contained function () and the contained value (f a) and will return a contained value (f b).
Apply f => f (a->b) -> f a -> f b
You can also use <*>
in combination with <$>
or in other words
with fmap
:
sumMaybe2 :: (Num a) => Maybe a -> Maybe a -> Maybe a
sumMaybe2 b c = (+) <$> b <*> c
Sometimes is easy to think that whenever you used to have a function receiving plain values you can use the same function but combining it as an applicative functor.
E.g here we have a function that creates a Band
:
data Band = Band { id :: Long,
name :: String,
year :: Int}
createBand :: Long -> String -> Int -> Band
createBand id name year = Band { id = id, name = name, year = year }
That’s perfect, but what happens when have to create a Band from Maybe instances ? No problem, let’s use applicative functors:
createBand2 :: Maybe Long -> Maybe String -> Maybe Int -> Maybe Band
createBand2 id name year = createBand <$> id <*> name <*> year
What I’m doing is to partially apply the applied function with the first parameter, then with the second, and finally we resolve the function within the context.
List comprehensions
There is another use I’ve found specially interesting. The use of
applicative functors for list comprehensions. Lets say I would like to
increment every value from a given list. We can use map
:
produceInc0 :: (Num a) => [a] -> [a]
produceInc0 xs = map (+1) xs
Or you may use list comprehensions:
produceInc1 :: (Num a) => [a] -> [a]
produceInc1 xs = [x + 1 | x <- xs ]
But there is still another way thanks to the applicative functor
function <*>
:
produceInc2 :: (Num a) => [a] -> [a]
produceInc2 xs = [(+1)] <*> xs