Are you curious about monads? đ¤ Or maybe youâre further down the rabbit đ° hole, looking into applicatives? Does âfunctorâ sound alien đ˝ to you?

No worries! đ

Monad, applicative functor, and functor are just functional programming patterns you can use to deal with effects like lists/arrays, trees, hashes/dictionaries, and even functions.

Functor is the simplest pattern, so it makes sense to start there. As you work your way to monad, youâll see that functor is the basis for applicative functor which is the basis for monad.

â ď¸ If you donât get the animations, donât worry. Just focus on the code samples and explanations. The animations are there for some visual intuition. đ

# Whatâs a functor?

## A functor is a list.

map(function)(list) = [function(element) | element <- list]add1(input) = input + 1map(add1)([1,2,3])-- [2,3,4]

The list functor takes a function and applies it to every element inside the list. The function doesnât have to consider or worry about the list â `map`

handles the list.

## A functor is a function.

map(function1)(function2)(input) = function1(function2(input))

sub2(input) = input - 2map(add1)(sub2)(1)

-- 0

The function functor composes or glues two functions together returning a new function. This new function routes its input through the two functions returning the output of the first function.

## A functor is a promise.

map(function)(promise) = fmap(function)(promise)promise <- async(return 11)wait(map(sub2)(promise))

-- 9

The promise functor applies a function to its fulfilled input and returns a new promise that will contain the output of the function.

## A functor is an effect that you lawfully define `map`

for.

`map`

:: (input -> output) -- Takes a function.

-> effect(input ) -- Takes input inside an effect.

-> effect( output) -- Returns output inside an effect.

In general, a functor is just `map`

defined for some effect. The `map`

function

- takes a function
`input -> output`

, - takes input for that function stuck inside an effect
`effect(input)`

, - passes the
`input`

to the function, - collects the functionâs
`output`

, - and returns the
`output`

stuck inside the effect`effect(output)`

.

# Wait, what do you mean by âlawfully define?â

The `map`

definition must obey the functor laws.

## How many functor laws are there?

There are two laws your `map`

definition must obey.

## Okay, whatâs the first law?

If you pass identity to `map`

, `map`

âs output must equal its input.

list = [1,2,3]identity(input) = inputlist == map(identity)(list)

-- True

## Hmm, whatâs the second and last law?

If you compose two or more functions and pass that to `map`

, `map`

âs output must equal the output of composing multiple calls of `map`

togetherâ one for each function.

times3(input) = input * 3composition(input) = add1(sub2(times3(input)))composition(1)

-- 2list = [1,2,3]map(composition)(list) == map(add1)(map(sub2)(map(times3)(list)))

-- True

One call to `map`

using `composition`

and `list`

equaled three calls to `map`

using `add1`

, `sub2`

, and `times3`

and `list`

.

# So functor is an interface?

Yes. If you define a lawful version of `map`

for some effect, it is an instance of functor or *mappable*. `map`

is an overloaded function that is defined differently for each type of effect you define it for.

If youâve used the usual map for lists/arraysâ found in most standard libraries â youâve been using functors all along. đş

# What do you mean by effect?

List/Array is an effect. Tuple/Struct/Record is an effect. Future/Promise is an effect. Function is an effect. Tree is an effect. HashMap/Hash/Dictionary is an effect. Maybe/Optional/Nullable is an effect. Either (or the more specialized try) is an effect. There are many effects. These are some of them.

Ask what an effect is and youâll see or hear âcontextâ, âfunctorial contextâ, âcontainerâ, âcontainer and payloadâ, âwrapperâ, âboxâ, âcomputationâ, âambiguous computationâ, âstructuresâ, âdata structuresâ, ânondeterminismâ, ânondeterministicâ, âtype constructorsâ, âside-effectsâ, âa side-effect made explicitâ, âimpureâ, and/or ânot pureâ. Phew.

The definition of effect is âpower to bring about a resultâ. This is true for anything Iâve seen called an effect. They *have* the power or capability to bring about a result but may not always. For example, the empty list/array or nothing/none/null for maybe/optional/nullable.

# I still donât get functor.

A functor lifts or upgrades a function from one that **cannot** operate on an effect to one that **can** work on a ** single** effect, leaving the effect

**intact**after the function is done.

In terms of an interface, if you want some effect to be a functor, you have to (lawfully) define map for it.

# Can map accept a function with more than one parameter?

If some function takes more than one parameter and you `map`

it over some functor, it will be partially applied and stuck in the effect.

Take lists for example.

add(left)(right) = left + rightmap(add)([1,2,3])

-- [ add(1),

-- add(2),

-- add(3) ]

`add`

was partially applied to `1`

, `2`

, and `3`

making for three partial applications of `add`

stuck inside the list. Partially applied meaning the function is waiting on its other parameters. `add(1)`

for example is waiting on one more number.

`[ add(1),`

add(2),

add(3) ]

â ď¸ At this point youâre stuck. You canât feed this result back into `map`

in order to supply more input to the `add`

s. `map`

doesnât take partially applied functions â waiting inside an effect/list â so youâll need applicative functor to work with this result.

# What are applicative functors?

## An applicative functor is a list.

pure(input) = [input]apply(functions)(list) =

[ element | function <- functions,

element <- map(function)(list)

]apply(pure(add1))([1,2,3])

-- [2,3,4]apply(apply(pure(add))([1,2,3]))([4,5,6])

-- [5,6,7,6,7,8,7,8,9]apply(map(add)([1,2,3]))([4,5,6])

-- [5,6,7,6,7,8,7,8,9]

It returns `[5, 6, 7, 6, 7, 8, 7, 8, 9]`

because it adds `1`

to `4`

, `5`

, and `6`

, adds `2`

to `4`

, `5`

, and `6`

, and then adds `3`

to `4`

, `5`

, and `6`

.

đĄ Instead of thinking about a list as a container for values, think of it as a nondeterministic value or put another way, a choice.

The list applicative functor computes all of the possible combinations or choices when sequencing or composing lists. You can represent this as a tree.

Anyway, notice how I had to use one apply for every parameter `add`

takes. One for the first parameter and another one for the second parameter.

The `pure`

and first `apply`

call wrapped three partially applied `add`

s inside a list but you can substitute the `pure`

and one `apply`

call with `map`

as using `add`

with `map`

also wraps three partially applied `add`

s inside a list. We saw this up above with functor.

apply(pure(add))([1,2,3])

-- [ add(1),

-- add(2),

-- add(3) ]map(add)([1,2,3])

-- [ add(1),

-- add(2),

-- add(3) ]

đ¤ So far all of the examples had non-empty lists but what happens if any one list is empty?

`[ ] `apply` [1,2,3] `apply` [4,5,6]`

-- []

[add] `apply` [ ] `apply` [4,5,6]

-- []

[add] `apply` [1,2,3] `apply` [ ]

-- []

You get an empty list. Tracing the implementation, you can see that if any one list is empty, it propagates out. Doesnât matter what the other lists had, youâll always get an empty list if any one of the lists are empty.

If any of the effects are empty or failed, for the list effect and others (like maybe or either), the first occurrence will spill out in the end. This works out nicely as you donât have to consider the empty case when applying lists or even worse, experience a crash because you ended up with an empty list somewhere.

đĄOne of the big aspects of applicative functor is that the effects *play out* before the lifted/upgraded function can do its thing. Applicative functor is like the Ronco â set it and forget it â showtime rotisserie đ of functional programming patterns. Once weâve kicked off the process, we can only wait for the end result.

Thereâs no picking and choosing whatâs next based on whatâs already occurred. We donât get to look at an intermediate result and make a decision. Itâs been said that applicative functor is batch versus interactive processing as is the case with monads.

Letâs say we have a function called `if_x_then_y_else_z`

(example adapted from *Applicative Programming with Effects, Conor McBride and Ross Paterson. in Journal of Functional Programming 18:1 (2008), pages 1â13*).

if_a_then_b_else_c(a)(b)(c) = if a then b else cpure(if_a_then_b_else_c) `apply` x `apply` y `apply` z

It takes in three effects and depending on `x`

âs result, it either picks the result from `y`

or `z`

. Since weâre talking about lists at this point, letâs use the list applicative functor.

if_x_then_y_else_z([True])(["y result"])(["z result"])

-- ["y result"]if_x_then_y_else_z([False])(["y result"])(["z result"])

-- ["z result"]

So if an item of `x`

is `True`

, we go with `y`

âs item else we go with `z`

âs.

`if_x_then_y_else_z([True])(["y result"])(["z result"])`

-- ["y result"]

For the inputs

`[True]`

`["y result"]`

- and
`["z result"]`

it doesnât matter what `z`

holds as itâll never be used. But notice what happens when `z`

is empty.

`if_x_then_y_else_z([True])(["y result"])([])`

-- []

You get an empty list even though the `z`

list isnât needed since `x`

holds a single `True`

. But like I wrote up above, if any of the lists are empty, the result will be empty too.

You could try to get around this by lifting/upgrading a function that returns a list.

if_x_then_y_else_z(x)(y)(z) =

apply(pure(\ a -> if a then y else z))(x)if_x_then_y_else_z([True])(["y result"])([])

-- [["y result"]]

â ď¸ But now youâre stuck. You have nested effects or in this case, nested lists. Later on, youâll see how the list monad deals with this situation.

đĄThe big thing to remember with applicative functor is that the lifted/upgraded function cannot change/influence the *shape* of the effect at any time. For `list`

, the shape would be the size. For `maybe`

the shape would be `just`

or `nothing`

. For `either`

the shape would be `left`

or `right`

.

Without running the applicative functor, you can determine the resulting shape just by looking at the shape of the effects given. Given an empty list? Youâre going to get an empty list. Given `[1,2]`

and `[3,4,5]`

? Youâre going to get back a list with six items.

With monads itâs different. They *can* change the shape because they *can* look at the intermediate results and decide what to do next.

## An applicative functor is a function.

pure(function)(ignore) = functionpure(add1)(Nothing)(0)

-- 1apply(wrapped_function)(function)(input) =

map(wrapped_function(input))(function)(input)apply(pure(add1))(add1)(1)

-- 3(pure(add) `apply` add1 `apply` add1)(1)

-- 4

The `pure`

definition for functions is just the constant (`const`

) function. The constant function takes two parameters and returns the first one ignoring the second one. So calling `pure(add1)(Nothing)`

wraps and then unwraps `add1`

. You can unwrap using any input youâd like as constant will just ignore it.

pure(add1)("Ignore this?")(1)

-- 2pure(add1)(concat ["Ignore"," this?"])(1)

-- 2

Notice how I chained as many calls to `apply`

as how ever many parameters the function took. I used one `apply`

for `add1`

and two calls of `apply`

for `add`

.

add_x_y_z(x)(y)(z) = add(add(x)(y))(z)add_x_y_z(2)(2)(2)

-- 6(pure(add_x_y_z)

`apply` add1

`apply` add1

`apply` add1)(1)

-- 6

The three calls to `apply`

â one for `x`

, one for `y`

, and one for `z`

â returns `6`

because

`1`

gets added to`1`

making`x`

equal`2`

`1`

gets added to`1`

making`y`

equal`2`

`1`

gets added to`1`

making`z`

equal`2`

- and finally
`x`

,`y`

, and`z`

get added together for a total of`6`

.

apply(pure(add_x_y_z))(add1)(1)(2)(3)

-- 7add_x_y_z(add1)(2)(3)

-- 7

You donât have to chain a call to `apply`

for every argument. In this example, I modified the `x`

parameter with `add1`

but passed `2`

as `y`

and `3`

as `z`

directly to `add_x_y_z`

.

add1(input) = 1 + input

sub2(input) = 2 - input

sub3(input) = 3 - input

(pure(add_x_y_z) `apply` add1 `apply` sub2 `apply` sub3)(4)

-- 2add1(4) + sub2(4) + sub3(4)

-- 2(1 + 4) + (2 - 4) + (3 - 4)

-- 2

If you do modify every parameter with `apply`

, the resulting function will only accept one input which will go to every modified parameter. In this example, `2`

went to every modified parameter of `add_x_y_z`

.

first = \ (a,b,c) -> a

second = \ (a,b,c) -> b

third = \ (a,b,c) -> c new_add_x_y_z =

pure(add_x_y_z) `apply` first `apply` second `apply` third new_add_x_y_z(1,2,3)

-- 6

If the form of your input data doesnât match the parameter signature of your function, using apply to compose your function with some other functions comes in handy. In this example, the data was in a tuple so I composed `add_x_y_z`

with `first`

, `second`

, and `third`

to extract and then add together `1`

, `2`

, and `3`

.

extract_then_add_x_y_z(t) =

add_x_y_z(first(t))(second(t))(third(t)) extract_then_add_x_y_z(1,2,3)

-- 6

Granted, I couldâve done it like the example above but applicative functor gives us a nicely generalized interface for modifying the input to some function with other functions.

first = \ (a,b) -> a

second = \ (a,b) -> bnew_add_x_y_z = pure(add_x_y_z) `apply` first `apply` secondnew_add_x_y_z(1,2)(3)

-- 6

If say, part of my data was in a tuple, I only have to reason about `apply`

and `pure`

instead of coming up with a specific function to handle this particular scenario.

## An applicative functor is a functor that you lawfully define pure and apply for.

pure

:: input -- Takes some input.

-> effect(input) -- Returns it inside an effect.apply

:: effect(input -> output) -- Takes a function in an effect.

-> effect(input ) -- Takes input in an effect.

-> effect( output) -- Returns output in an effect.

In general, an applicative functor is a functor that you define `apply`

and `pure`

for. The `apply`

function

- takes a function inside an effect
`effect(input -> output)`

, - takes input for that function inside an effect
`effect(input)`

, - applies the function to the input,
- and returns the functionâs output inside the effect
`effect(output)`

.

đĄ Compare it to map and youâll see the subtle change â the function is now in the effect too.

map

:: (input -> output) -- Takes a function.

-> effect(input ) -- Takes input inside an effect.

-> effect( output) -- Returns output inside an effect.apply

:: effect(input -> output) -- Takes a function in an effect.

-> effect(input ) -- Takes input in an effect.

-> effect( output) -- Returns output in an effect.

đ Look again but in this condensed form.

`map :: (i -> o) -> e(i) -> e(o)`

apply :: e(i -> o) -> e(i) -> e(o)

-- ^ The big difference.

Thatâs the main and only difference between `apply`

and `map`

.

# Lawfully, meaning applicative functor has laws too?

Yes. There are four applicative functor laws.

# So applicative functor is an interface too?

Yes. If there are lawful definitions of `pure`

and `apply`

for some functor, it is an instance of applicative functor. In other words, applicative functor extends the functor interface with `pure`

and `apply`

.

# I still donât get applicative functor.

Applicative functor picks up where functor leaves off. Functor lifts/upgrades a function making it capable of operating on a ** single** effect. Applicative functor allows the sequencing of

*multiple***effects. Functor deals with one effect while applicative functor can deal with multiple independent effects. In other words, applicative functor generalizes functor.**

*independent*In terms of an interface, applicative functor adds `pure`

and `apply`

to functorâs `map`

.

## What do you mean by independent effects?

Independent meaning some effect does not rely on the outcome of some other effect.

x = [1,2]

y = [3,4]

z = [5,6]pure(add) `apply` (pure(add) `apply` x `apply` y) `apply` z

-- [9,10,10,11,10,11,11,12]

In this example, we sequence three effects or lists. Neither `x`

, `y`

, nor `z`

rely on the outcome of any other. Since theyâre all independent, we could process the final result in parallel or simultaneously. This is one of the advantages to applicative functor.

`[ 1+3+5=09,`

1+3+6=10,

1+4+5=10,

1+4+6=11,

2+3+5=10,

2+3+6=11,

2+4+5=11,

2+4+6=12 ]

Now say we lift/upgrade the following function for the list instance.

`add1_inside_effect(input) = pure(input + 1)`

It will return a dependent effect/list dependent on some item `input`

from some other list.

pure(add1_inside_an_effect) `apply` x

-- [[2],[3]]pure(add) `apply` (pure(add1_inside_an_effect) `apply` x)

-- error!

Applicative functor only deals with independent effects. If you have a dependent effect, youâll need monads as youâll see next.

# What is a monad?

## A monad is a list.

join(nested_lists) =

[element | list <- nested_lists, element <- list]join([[1], [2, 3], [4, 5, 6]])

-- [1, 2, 3, 4, 5, 6]join(apply(pure(\ x -> [x + 1, 1]), [1,2,3]))

-- [2, 1, 3, 1, 4, 1]join(

apply(

pure(\ x -> [2, x * 3, x * 4]))(

join(

apply(

pure(\ x -> [x + 1, 1]))(

[1,2,3]))))

-- [2,6,8,2,3,4,2,9,12,2,3,4,2,12,16,2,3,4]

The big and only addition for the monad interface is `join`

. `join`

flattens or better put, peels off an effect from two nested effects. For the list instance, `join`

is just `concat`

.

Join only deals with nested effects that are the same type and nested one level deep. So for example, `[[1], [3,4]]`

, `just(just(1))`

, `right(right(2))`

but not `[just(1), just(left(1))]`

, `[1, [2]]`

, `[[[1]]]`

, etc.

if_x_then_y_else_z =

pure(\ a -> if a then y else z) `apply` xif_x_then_y_else_z([True])(["y result"])([])

-- [["y result"]]

When we previously lifted/upgraded a function that returned a list (to get around `z`

being empty), we ended up with a nested list. Back then we were stuck but `join`

allows us to keep on truckinâ đ. Now you can pick either the `y`

or `z`

list based on the items in `x`

and ** not** end up with a nested list.

if_x_then_y_else_z(x)(y)(z) =

join(pure(\ a -> if a then y else z) `apply` x)if_x_then_y_else_z(

[True,False,False,True])(

["y result"])(

["z result"])

-- [ "y result", True so return y.

-- "z result", False so return z.

-- "z result", False so return z.

-- "y result" ] True so return y.

đĄ Therein lies the power of monads, they allow us to pick the next effect based on the result from a previous effect. In other words, monad allows us to sequence dependent effects or better put, sequence functions that return effects.

â ď¸ Note that âpick the next effectâ doesnât mean you can, at some point, change the type of effect you return. For example, you canât suddenly decide to return a maybe if youâre operating in the list monad. A monad is also a functor, so in the end, the effect must remain intact with only its results potentially altered.

## A monad is a function.

join(wrapped_function)(input) =

wrapped_function(input)(input)join(apply(pure(add))(add1))(1)

-- 3add(add(1)(1))(1)

-- 3add(2)(1)

-- 3(1 + 1) + 1

-- 3divide(numerator)(denominator) = numerator / denominatorjoin(

apply(

pure(divide))(

join(

apply(

pure(add))(

add1))))(2)

-- 2.5divide(

add(

add(

1)(

2))(

2))(

2)

-- 2.5divide(

add(

3)(

2))(

2)

-- 2.5divide(

5)(

2)

-- 2.5(((1 + 2) + 2) / 2)

-- 2.5

The function monad allows you to sequence or compose functions together. The first function in the chain can only take one parameter and the rest have to take two parameters.

After youâre done composing functions together using `join`

, `apply`

, and `pure`

, the returned function will only take one input. This single input will start a chain reaction.

- The first function takes only one parameter.
- It receives the input and returns some output.
- The second function takes two parameters.
- It receives the output from function one, the input, and returns some output.
- The third function takes two parameters.
- It receives the output from function two, the input, and returns some output.
- The fourth functionâŚand on and on for how ever many functions you sequenced.

## A monad is an applicative functor that you lawfully define join for.

`join`

:: effect(effect(data))

-> effect(data)

In general, a monad is just an applicative functor you define `join`

for.

# So monads are just applicative functors with join added to the interface?

Yes.

# How many laws are there for monad?

There are three monad laws.

# What about return and bind?

Bind is just a convenience function that composes `join`

, `apply`

, and `pure`

.

bind(effect)(function) = join(apply(pure(function))(effect))[1,2,3] `bind` \ x -> [x + 2]

-- [3,4,5][1,2,3] `bind` \ x -> [x + 2] `bind` \ y -> [y * 3]

-- [9,12,15][1,2,3] `bind` \ x -> pure(x + 2) `bind` \ y -> [y * 3, 0]

-- [9,0,12,0,15,0](add1 `bind` add `bind` divide)(2)

-- 2.5

Or if you prefer, `bind`

composes `join`

and `map`

together.

bind(effect)(function) = join(map(function)(effect))[1,2,3] `bind` \ x -> pure(x + 2) `bind` \ y -> [y * 3, 0]

-- [9,0,12,0,15,0]

`return`

is just `pure`

.

`return = pure`

# Can you summarize them for me?

- Functor lifts or upgrades a function, allowing it to operate on a single effect, leaving the effect intact after itâs done. It requires a lawful
`map`

definition. - Applicative functor builds on or generalizes functor, allowing you to sequence multiple independent effects. It requires a lawful
`pure`

and`apply`

definition. - Monad builds on or generalizes applicative functor, allowing you to sequence independent and/or dependent effects. It requires a lawful
`join`

definition.

`map :: (i -> o ) -> e(i) -> e(o) -- Functor`

apply :: e(i -> o ) -> e(i) -> e(o) -- Applicative

bind :: (i -> e(o)) -> e(i) -> e(o) -- Monad

^ ^

If youâd like to see what you can do with functors, applicatives, and monads, check out Movie Monad and Gifcurry â two desktop GUI apps created with Haskell, a purely functional programming language.

For more information about functors, applicatives, monads, and other functional programming patterns, take a look at Typeclassopedia by Brent Yorgey*.*