# Functor, Applicative, and Why

This blog post will explain two core concepts in Haskell — Functor and Applicative, which also exist in many other functional languages. Functor and Applicative are great abstractions that allow us to reuse lots of code.

However, when I was learning these concepts, it was difficult for me. Not just because they’re abstract, but because most of the articles and posts I read about Functor and Applicative start by introducing their definition and then give examples.

I feel it should be the other way around. It’s easier to learn abstract things by seeing concrete instances or use cases of them.

So in this post, I’m starting with concrete examples then tying them back to the definitions of Functor and Applicative.

# Input validation

Let’s say we have a `greet`

function in Javascript that takes a user object and returns a string:

`var greet = function(user) {`

return "Hello " + user.name;

};

If we try it in the node REPL, it should work.

`> greet({ name: "Alice" })`

'Hello Alice'

However, if we enter an `undefined`

value, it will throw an exception.

`> greet(undefined)`

TypeError: Cannot read property 'name' of undefined

...

Why would the `user`

be `undefined`

?

Well, Javascript is an untyped language, so any variable could be `undefined`

. This function assumes the input is not `undefined`

. But it's common for developers to forget about this assumption.

In order to handle the `undefined`

input, we could wrap this function with a function that validates the input:

`var checkAndGreet = function(user) {`

if (!user) {

return undefined;

}

return greet(user);

};

So if the user is `undefined`

, we wouldn't pass it to `greet`

, but short circuit to return `undefined`

.

`Maybe`

type in Haskell

Let’s see how this case is handled in Haskell.

First, let’s define the `User`

type and the `greet`

function.

data User = User String

deriving (Show)greet :: User -> String

greet (User name) = "Hello " ++ name

Test it in GHCi:

> User "Alice"

User "Alice"> greet (User "Alice")

"Hello Alice"

And let’s visualize the function call like this:

In Haskell, this case is handled by a data type called `Maybe`

. This is the type declaration of `Maybe`

, which says the generic `Maybe`

type is either a `Just`

value that contains other values, or a constant `Nothing`

value.

`data Maybe a = Nothing | Just a `

deriving (Eq, Ord)

So `Maybe User`

is a type that can present two cases, either `Nothing`

or a `Just User`

.

If the input is a `Maybe User`

, then we can make a `checkAndGreet`

to take that and return a `Maybe String`

.

`checkAndGreet :: Maybe User -> Maybe String`

checkAndGreet Nothing = Nothing

checkAndGreet (Just user) = Just (greet user)

The first line defines the `Maybe`

Let’s try it in GHCi

> checkAndGreet Nothing

Nothing> user = User "Alice"> checkAndGreet (Just user)

Just "Hello Alice"

# How does it prevent mistakes?

Where would we get a `Maybe User`

?

Well, let’s say we don’t want the user name to be empty, so we can create a `validateAndMakeUser`

function to check if the name is empty and returns a `Maybe User`

.

`validateAndMakeUser :: String -> Maybe User`

validateAndMakeUser "" = Nothing

validateAndMakeUser name = Just (User name)

Let’s look at the mistake we had before.

If we have a user name of `String`

and we forget to validate the name and pass it directly to `greet`

, the Haskell compiler won't allow it. The compiler will say `greet`

takes a `User`

, which is not a `String`

.

`> greet "Alice"`

error:

• Couldn't match expected type ‘User’ with actual type ‘[Char]’

• In the first argument of ‘greet’, namely ‘"Alice"’

In the expression: greet "Alice"

In an equation for ‘it’: it = greet "Alice"

If we remember to validate the name, and now we have a `Maybe User`

value, but still we passed it to `greet`

instead of `checkAndGreet`

, then the code won't compile either. Because `Maybe User`

and `User`

are different types.

> greet (Just (User "Alice"))<interactive>:20:8: error:

• Couldn't match expected type ‘User’ with actual type ‘Maybe User’

• In the first argument of ‘greet’, namely ‘(Just (User "Alice"))’

In the expression: greet (Just (User "Alice"))

In an equation for ‘it’: it = greet (Just (User "Alice"))

# Extract the input validation part into a function

Alright. Let’s say we have other functions that take `User`

and returns a different `String`

, for instance, a `bye`

function:

`bye :: User -> String`

bye (User name) = "Goodbye " ++ name

However, the input value we have is a `Maybe User`

value, not a `User`

. How can I take the `User`

from the `Maybe User`

and pass it to the `bye`

function?

Then we can wrap it the same way as `checkAndGreet`

to make a `checkAndBye`

.

`checkAndBye :: Maybe User -> Maybe String`

checkAndBye Nothing = Nothing

checkAndBye (Just user) = Just (bye user)

As you probably noticed, the `checkAndGreet`

and `checkAndBye`

are very similar. We're kind of repeating the logic here.

We could extract the common part into a function, and use that to make `checkAndGreet`

and `checkAndBye`

. Let's name this common function `mapUser`

.

mapUser :: (User -> String) -> Maybe User -> Maybe String

mapUser f Nothing = Nothing

mapUser f (Just user) = Just (f user)checkAndGreet :: Maybe User -> Maybe String

checkAndGreet maybeUser = mapUser greet maybeUsercheckAndBye :: Maybe User -> Maybe String

checkAndBye maybeUser = mapUser bye maybeUser

We can further refactor them into point-free style:

checkAndGreet :: Maybe User -> Maybe String

checkAndGreet = mapUser greetcheckAndBye :: Maybe User -> Maybe String

checkAndBye = mapUser bye

With the generic `mapUser`

, you can get `checkAndGreet`

and `checkAndBye`

for free.

# Generalize the `mapUser`

function

Let’s take a look at the `mapUser`

function again. Even though this function is called `mapUser`

, it didn't actually use anything special about `User`

, nor about `String`

`mapUser :: (User -> String) -> Maybe User -> Maybe String`

mapUser f Nothing = Nothing

mapUser f (Just user) = Just (f user)

If we replace `User`

with a generic type `a`

and replace `String`

with a generic type `b`

, then `mapUser`

is equivalent to the `mapMaybe`

function as below:

`mapMaybe :: (a -> b) -> Maybe a -> Maybe b`

mapMaybe f Nothing = Nothing

mapMaybe f (Just a) = Just (f a)

Then we can refactor the `checkAndGreet`

and `checkAndBye`

with the `mapMaybe`

function, and it will still type-check and work.

checkAndGreet :: Maybe User -> Maybe String

checkAndGreet = mapMaybe greetcheckAndBye :: Maybe User -> Maybe String

checkAndBye = mapMaybe bye

Now we have a generic `mapMaybe`

function that can deal with a case where the input is empty (`Nothing`

).

With Haskell’s strong type system, we can just write functions that process on concrete types, and if we need those functions to process the Maybe values we get them from DB calls or HTTP request, we can now just wrap the function with `mapMaybe`

to get a new function that is able to process over `Maybe`

values.

The `mapMaybe`

function can be implemented in Javascript too. Given there is no `Maybe`

type, we would just call it `mapNullable`

:

var mapNullable = function(f) {

return function(v) {

if (v === null || v === undefined) {

return null;

}

return f(v);

};

};var greet = function(user) {

return "Hello " + user.name;

};var bye = function(user) {

return "Bye " + user.name;

};var checkAndGreet = mapNullable(greet);

var checkAndBye = mapNullable(bye);console.log(checkAndGreet({ name: 'Alice' })); // "Hello Alice"

console.log(checkAndBye(undefined)); // undefined

# Map over 2 `Maybe`

values

Let’s back to our Haskell version. We have a generic `mapMaybe`

to map a function over a `Maybe`

value. But it seems to only work for functions that take just one argument.

`mapMaybe :: (a -> b) -> Maybe a -> Maybe b`

What if my function takes more than one argument? Is it possible to have a function that maps over multiple `Maybe`

values? For example, `map2Maybes`

and `map3Maybes`

with the following type signatures:

map2Maybes :: (a -> b -> c) -> Maybe a -> Maybe b -> Maybe cmap3Maybes :: (a -> b -> c -> d)

-> Maybe a

-> Maybe b

-> Maybe c

-> Maybe d

And let’s call a function that takes `N`

arguments an "N-arity" function. So `mapMaybe`

is 1-arity function, and `map2Maybes`

is 2-arity function, `map3Maybes`

is 3-arity function.

If we have the `map2Maybes`

function, then we can use it to wrap a function that takes two `Maybe User`

values as input.

showParents :: User -> User -> String

showParents (User fatherName) (User motherName) =

"Father is " ++ fatherName ++ " and mother is " ++ motherNamecheckAndShowParents :: Maybe User -> Maybe User -> Maybe String

checkAndShowParents maybeFather maybeMother =

map2Maybes showParents maybeFather maybeMother

And the `map2Maybes`

is not hard to implement:

`map2Maybes :: (a -> b -> c) -> Maybe a -> Maybe b -> Maybe c`

map2Maybes _ Nothing _ = Nothing

map2Maybes _ _ Nothing = Nothing

map2Maybes f (Just a) (Just b) = Just (f a b)

Similarly, you can implement `map3Maybes`

, `map4Maybes`

... We can make as many as we want. However, we still need to write them manually each time for wrapping an N-arity function.

Is it possible to have a generic `mapNMaybes`

function that works for functions that take any number of arguments?

Let’s find out.

# Map over N Maybe values

In Haskell, every function is curried. We can pass a value to a 2-arity function to get a new 1-arity function.

`> :t showParents (User “Bob”)`

showParents (User “Bob”) :: User -> String

Therefore, `showParents`

's type signature could also be written as:

`showParents :: User -> (User -> String)`

If we treat the 1-arity function `(User -> String)`

as a value, then `showParents`

can be passed to `mapMaybe`

and it will return a `Maybe (User -> String)`

type

`> :t mapMaybe showParents (Just (User “Bob”))`

mapMaybe showParents (Just (User “Bob”)) :: Maybe (User -> String)

But wait a second, can a `Maybe`

type contain a function?

Yes, why not? `Maybe a`

is a generic type, and it can take any concrete type to make a new type. Since a function is also a concrete type, it can be wrapped in a `Maybe`

value too. And it doesn't matter how many arguments it takes.

For instance, we can just pass any function to one of the Maybe type constructor `Just`

:

> :t Just greet

Just greet :: Maybe (User -> String)> :t Just showParents

Just showParents :: Maybe (User -> User -> String)

But what can we do with a `Maybe (User -> String)`

value?

Well, let’s take a look at what we need. We’d like to implement a `checkAndShowParents`

function.

`checkAndShowParents :: (User -> User -> String) `

-> Maybe User

-> Maybe User

-> Maybe String

Since we’ve got

`mapMaybe :: (User -> (User -> String)) `

-> Maybe User

-> Maybe (User -> String)

Or

`mapMaybe :: (User -> User -> String) `

-> Maybe User

-> Maybe (User -> String)

If we have another function with the following type signature, let’s call it `applyShowParents`

for now.

`applyShowParents :: Maybe (User -> String) `

-> Maybe User

-> Maybe String

Then we can composite it with the `mapMaybe`

to make `checkAndShowParents`

:

checkAndShowParents :: Maybe User -> Maybe User -> Maybe String

checkAndShowParents maybeFather maybeMother =

applyShowParents (mapMaybe showParents maybeFather) maybeMotherapplyShowParents :: Maybe (User -> String)

-> Maybe User

-> Maybe String

applyShowParents Nothing _ = Nothing

applyShowParents _ Nothing = Nothing

applyShowParents (Just f) (Just user) =

Just (f user)Generalize to applyMaybe

Again, we can generalize the `applyShowParents`

as well into a generic `applyMaybe`

function, because the function body doesn't need anything special from either `User`

or `String`

.

`applyMaybe :: Maybe (a -> b) -> Maybe a -> Maybe b`

applyMaybe Nothing _ = Nothing

applyMaybe _ Nothing = Nothing

applyMaybe (Just f) (Just a) = Just (f a)

And the `checkAndShowParents`

can be implemented by compositing `mapMaybe`

, `applyMaybe`

and `showParents`

`checkAndShowParents :: Maybe User -> Maybe User -> Maybe String`

checkAndShowParents maybeFather maybeMother = applyMaybe

(mapMaybe showParents maybeFather) maybeMother

# Generalize into N-arity function

Now that we can map over 2-arity functions, can it apply to N-arity functions?

Yes. Observe the `applyMaybe`

's type signature and how we can use it for a 3-arity functions or N-arity too:

applyMaybe :: Maybe (a -> b -> c) -> Maybe a -> Maybe (b -> c)applyMaybe :: Maybe (a -> b -> c -> d)

-> Maybe a

-> Maybe (b -> c -> d)applyMaybe :: Maybe (a -> b -> c -> d -> e)

-> Maybe a

-> Maybe (b -> c -> d -> e)...

And with the following functions we can reduce a `Maybe`

N-arity function value into a `Maybe`

(N-1)-arity function value, which can be further reduced all the way to a `Maybe`

value.

> add3 a b c = a + b + c + (1 :: Int)> :t add3

add3 :: Int -> Int -> Int -> Int> :t applyMaybe (Just add3) (Just 1)

applyMaybe (Just add3) (Just 1) :: Maybe Int -> Maybe (Int -> Int -> Int)> :t applyMaybe (applyMaybe (Just add3) (Just 1)) (Just 2)

:t applyMaybe (Just add3) (Just 1) :: Maybe Int -> Maybe (Int -> Int)> :t applyMaybe (applyMaybe (applyMaybe (Just add3) (Just 1)) (Just 2)) (Just3)

:t applyMaybe (applyMaybe (applyMaybe (Just add3) (Just 1)) (Just 2)) (Just3) :: Maybe Int

The above expression looks a bit messy. Let’s rewrite it as infix operator.

> Just add3 `applyMaybe` (Just 1) `applyMaybe` (Just 2) `applyMaybe` (Just 3)

Just 7> Just add3 `applyMaybe` Nothing `applyMaybe` (Just 2) `applyMaybe` (Just 3)

Nothing

# Pattern of writing input validation for functions

We’ve made a generic `mapMaybe`

function and an `applyMaybe`

function that can be used to wrap any N-arity functions. That way, they're able to take values from N `Maybe`

and shortcircuit to return `Nothing`

if any of the N Maybe values are `Nothing`

.

greet :: User -> String

greet (User name) = "Hello " ++ namecheckAndGreet :: Maybe User -> Maybe String

checkAndGreet = mapMaybeshowParents :: User -> User -> String

showParents (User fatherName) (User motherName) =

"Father is " ++ fatherName ++ " and mother is " ++ motherNamecheckAndShowParents :: Maybe User -> Maybe User -> Maybe String

checkAndShowParents maybeFather maybeMother =

showParents `mapMaybe` maybeFather `applyMaybe` maybeMotheradd3 :: Int -> Int -> Int -> Int

add3 a b c = a + b + c + 1checkAndAdd3 :: Maybe Int -> Maybe Int -> Maybe Int -> Maybe Int

checkAndAdd3 ma mb mc = add3 `mapMaybe` ma

`applyMaybe` mb

`applyMaybe` mc

You might notice a pattern here: if we want to wrap an `N-arity`

function with empty input checks and the function has only 1 argument, we can just use `mapMaybe`

. If there is more than 1 argument, we just append (`applyMaybe`

argN) in the end.

# Functor and Applicative

OK, with the above examples and practices in mind, now it’s time to introduce the term `Functor`

and `Applicative`

.

What is `Functor`

? `Functor`

is a typeclass that essentially defines a list of functions to implement.

`Functor`

typeclass defines just one function `fmap`

with the following type signature.

`class Functor f where`

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

Recall the `mapMaybe`

function we created earlier. It's the `fmap`

function for `Maybe`

to be a `Functor`

. In other words, `Maybe`

is a `Functor`

because `Maybe`

implements `fmap`

:

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

mapMaybe f Nothing = Nothing

mapMaybe f (Just a) = Just (f a)instance Functor Maybe where

fmap = mapMaybe

`fmap`

is also defined as the inflx operator `<$>`

. Therefore, the following two operations are identical:

infixl 4 <$>

(<$>) :: Functor f => (a -> b) -> f a -> f b

(<$>) = fmapfmap greet (Just (User "Alice"))

greet <$> Just (User "Alice")

# What is `Applicative`

?

`Applicative`

is also a typeclass. To be an `Applicative`

, the type has also to be a `Functor`

.

`Applicative`

defines two functions, `pure`

and `<*>`

, with the following type signature:

`class Functor f => Applicative f where`

pure :: a -> f a

(<*>) :: f (a -> b) -> f a -> f b

`Maybe`

is an instance of `Applicative`

. Refer to the type signature of `Just`

and `applyMaybe`

: these two functions are `Maybe`

type's implementation for being `Applicative`

.

Just :: a -> Maybe aapplyMaybe :: Maybe (a -> b) -> Maybe a -> Maybe bclass Applicative Maybe where

pure = Just

(<*>) = applyMaybe

The abstraction of `Functor`

and `Applicative`

allows more generic functions to be built and reused. For example, the `liftA2`

and `liftA3`

are generic versions of the `map2Maybes`

and `map3Maybes`

for `Applicative`

.

liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f cliftA3 :: Applicative f => (a -> b -> c -> d)

-> f a

-> f b

-> f c

-> f d

Both `liftA2`

and `liftA3`

can be implemented with just `pure`

and `<*>`

. You can try to implement them yourself.

# More Functor examples

So far we’ve seen an instance of `Functor`

and `Applicative`

, which is `Maybe`

. Actually, there are a lot more of them defined in the base module, and other modules.

The most useful Applicatives (which also means they are `Functor`

s) are `Maybe`

, `Either`

, `IO`

and `List`

, which means you can use the same functions `fmap`

, `(<*>)`

on all those types.

For instance, `IO`

is also a `Functor`

and an `Applicative`

. Here is an example of how to read and parse environment variables with the functions provided by `Functor`

and `Applicative`

.

To read the environment variables by name, there is a `getEnv`

function under the namespace `System.Environment`

that takes `String`

as the env var name and returns the env var as `IO String`

.

`> import System.Environment (getEnv)`

> :t getEnv

getEnv :: String -> IO String

`IO String`

is a computation that might run into an exception. For instance,

> getEnv "NAME"

*** Exception: NAME: getEnv: does not exist (no environment variable)> ("NAME: " ++) <$> getEnv "NAME"

*** Exception: NAME: getEnv: does not exist (no environment variable)> ("PORT: " ++) <$> getEnv "PORT"

"4567"

And we can make a `readConfig`

function by reusing the `<$>`

and `<*>`

function like this:

data Config = Config

{ cfgHost :: String

, cfgPort :: Int

, cfgDebug :: Bool

} deriving (Show)readConfig :: IO Config

readConfig = Config <$> getHost

<*> getPort

<*> getDebug getHost :: IO String

getHost = getEnv "HOST"getPort :: IO Int

getPort = read <$> getEnv "PORT"getDebug :: IO Bool

getDebug = read <$> getEnv "DEBUG"

Notice that the `read`

function is a polymorphic parse function that can be either `String -> Int`

or `String -> Bool`

depending on where it's used.

So if the environment doesn’t have `HOST`

, then the `IO`

will throw an exception:

`> readConfig`

*** Exception: HOST: getEnv: does not exist (no environment variable)

If all the environment variables are present, we’ll get a `Config`

value with all the parsed value in it.

`> readConfig`

Config {cfgHost = "localhost", cfgPort = 4567, cfgDebug = True}

# Why?

To summarize my points with a few QnAs.

# So what is `Functor`

and `Applicative`

?

They are typeclasses (like interfaces in other languages) that define the functions that their type instances have to implement.

# Why do I need `Functor`

?

Because we want to reuse code.

`Functor`

generalizes how to map a function from one value to another. We used the `Maybe`

type as an example to show why and how to use a generic `mapMaybe`

function without having to deal with the empty case. And the `mapMaybe`

is the implementation of `Functor`

for `Maybe`

type.

# Why do I need `Applicative`

?

Because `Functor`

can only map a function which takes one argument. If we have a function that takes multiple arguments, we need `Applicative`

.

`Applicative`

provides abstraction for how to apply a function that takes multiple arguments over multiple values. We used `applyMaybe`

, which is the implementation of `Applicative`

for `Maybe`

type, as an example to show how to map a function over multiple `Maybe`

values without dealing with the case of any value being `Nothing`

.

# Why do I need `Functor`

and `Applicative`

instead of just `mapMaybe`

and `applyMaybe`

?

There are more instances of `Functor`

and `Applicative`

. For example, `Maybe`

, `Either`

, `IO`

, `List`

are all `Functor`

and `Applicative`

. You can reuse the same `fmap`

and `<*>`

function to map functions over those values without having to write `mapMaybe`

, `mapEither`

, `mapList`

, etc.

And functions like `liftA2`

, which is defined on top of `Functor`

and `Applicative`

, can also be reused for free without having to write `may2Maybes`

, `map2IOs`

, `map2Eithers`

etc.

# Conclusion

`Functor`

and `Applicative`

are two key concepts in functional programming. We used the `Maybe`

type and its use cases as examples to introduce the need for abstraction. `Functor`

and `Applicative`

are abstractions; they define what functions have to be implemented for a type to be an instance of them.

Functional programming has plenty more abstractions and type classes built on top of `Functor`

and `Applicative`

. This makes a great amount of code and logic reusable, and Haskell's strong type system ensures that the use of those generic functions are correct and safe.

Thanks for reading this blog post. Hopefully, I made `Functor`

and `Applicative`

a bit easier to understand.