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 + inputsub2(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) -> asecond = \ (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 independent effects. Functor deals with one effect while applicative functor can deal with multiple independent effects. In other words, applicative functor generalizes functor.

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.

`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.

`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.

Yes.

How many laws are there for monad?

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) -- Functorapply :: e(i ->   o ) -> e(i) -> e(o) -- Applicativebind  ::  (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.