A Conversation About Functional Programming, Monads and JavaScript

(I published this article on LinkedIn as well)

The following is part one of a conversation that took place recently between a friend (named Nicholay) and myself.

We both have adopted functional programming techniques to some degree with intention to gain the touted benefits such as easier to reason about code, simpler testing, thread safety and so on.

For me personally, my motivation comes from a need to build applications that I basically have no idea how they are going to change at the technical level or even how business requirements may evolve.

Under such circumstances, I have realized that the communication mechanisms between modules/components must be given particular attention. These mechanisms ultimately form the glue that keeps the application together and has significant impact on whether the application can be easily extended without breaking.

When applying pure functional programming, our functions have no side-effects, that is, they only accept input apply an algorithm and give us a result.

That means you can’t secretly access a database or open a socket in that function. Any function that does so must explicitly indicate that in the result somehow, it must not lie about what it does.

At first this seems cumbersome but that’s where monads come into play. Monads allow us describe and compose these side-effect-full operations essentially giving visible form to actions we would otherwise just do implicitly in imperative programs.

While I don’t think pure functional programming is a cure all remedy; working with pure functions so far has allowed me to be surprisingly more expressive than I usually am with Object Oriented code.

Background

After spending several hours (or days) trying to wrap my head around the Free monad. I was at a loss to figure out how I could actually use it to safely allow the type of monad interleaving I read about all over the Internet.

Nicholay challenged me to explain the concept of Monads, the idea being it may help me better understand the problem I was having.

I edited the conversation for easier reading and included some after thoughts (in italics).

The Conversation

Nicholay:

Since you’re concentrating on monads; what can you tell me about them? Attempting to explain them might help you to understand them better.

Me:

I can’t give you all the gory details but think of it like this:

[a], where [a] is a box containing a member of the set called ‘The English Alphabet’. In this case the letter ‘a’.

Nicholay

Okay.

Me:

Well we know that in math, a function takes an input ‘x’ and gives us some result ‘y’ right?

Nicholay:

Right.

Me:

That is to say let y = f(x).

So if we had a function called ‘f’ that for any letter in our alphabet, it maps (or transforms) them to a member of another set we call numbers:

f(a) = 1, f(b) = 2, f(c) = 3, f(d) = 4 … etc

Then we should be able to take [a] (the letter a in a box), apply the function ‘f’ and get [1] as the result right?

Nicholay:

Okay, go on.

Me:

Well f([a]) will not give us [1] because ‘f’ only works on letters, not letters in a box.

Nicholay:

Hmmm.

Me:

Look at it in pretend JavaScript/C/Go:

type box struct { value:char }
function f(v:char): int
let boxedA = box{‘a’}
f(boxedA) //Error````

You can’t apply ‘f’ to boxedA because it’s the wrong type!

Well in JavaScript you can, thanks to duck typing but in a strongly typed language you can’t. It won’t compile. A letter in a box is simply not the same as a letter.

Nicholay:

Ahh!

Me:

But we still want to be able to transform that letter in the box. We could get rid of the box and keep the letter but that’s like shipping food without containers!

What if our box provided a method to temporarily undress it, so we could access the value inside but on the condition that we put back on its clothes afterwards?

Something like this:

[a].undress(f) = [1]

Are you still there?

Nicholay:

Woah!

Me:

This is not a monad by the way.

Nicholay:

That seems more elegant than what I was thinking. So what is then?

Me:

Ahh, we call the box a Functor. That’s because it provides a way to ‘undress’ itself and change its internals then put back on clothes again. In Category Theory, as a i understand it (which I don’t) it’s not exactly the same thing but the effect is for our purposes.

That undress method is typically called ‘map’ because it allows us to ‘map’ the internal value to a new value without changing the type of the enclosure (the box). Kind of like how we have Array.prototype.map() in JavaScript.

Nicholay:

Okay, I think I’m still following.

Me:

Type this in your web browser (press CTL + Shift + ‘i’ together to bring up the console):

[1,2,3].map(function(x){ return x *x})

You should get back an array with all the values squared.

Nicholay:

Okay, now that’s familiar.

Me:

Yeah, though I don’t think it’s quite the same but forget about that for now.

(Is it? Is the List monad more or less an array or is a single linked list required?)

Now the reason for explaining Functors is that all monads happen to be Functors.

They utilize their Functor ability to do much more.

Nicholay:

Ah. I think I heard that before. Like safely containing side effects?

Summary

I’ll stop here in the interest of not making this post too long. Most of the conversation so far has been about Functors because I find Monads easier to ponder in terms of a map followed by a join.

Stay tuned for part two!