A little thread on monads...

(please don't get scared by the terms and run away! give it a shot!)
A monad is a container around a value (like a number, string, or func) that gives that value special additional behavior it wouldn't have otherwise. For example, it helps that monad interact predictable with other monads.

In that way, it's like a Collection or Data Structure.
Which behavior? Depends on what you're trying to do.

Here's an example you already will recognize:

arr = [ 1, 2, 3 ];
inc = v => v + 1;
http://arr.map (inc); // [2, 3, 4]
An array is a container holding multiple values. `map(..)` applies a func to all of them, and produces a new array container holding all the new values. You've almost certainly done that in code.

Turns out, this behavior is called "Functor". I know, it's a funny/scary word.
But we say an array is a functor because you can take one array and map it to another array.

Functor is also one of the common behaviors of monads.

A monad generally holds a single value, but a functor means it has a .map(..) call that can produce a new monad w/ the new value.
So...

three = Just(3);
inc = v => v + 1;
http://three.map (inc); // Just(4)

That's not so scary, right? Just is a functor monad so we can map to a new Just monad with a different value.
Another behavior you often have used with arrays (and strings, etc) is concatenating them together, right?

arr = [ 1, 2, 3 ];
arr2 = [ 4, 5, 6 ];
arr.concat(arr2); // [1,2,3,4,5,6]

This kind of behavior in monads is called "Concat(able)".
For our Just monad, it can also be given the concatable behavior:

arr = Just([ 1, 2, 3 ]);
arr2 = Just([ 4, 5, 6 ]);
arr.concat(arr2); // Just([1,2,3,4,5,6])

OK, not so bad, right?
Yet another kind of behavior you might like is for operations (like map(..), etc) to run ONLY if the value in the monad is non-empty, but skip the operations in the case of like null or undefined.

This is often what the Maybe monad is used for.
A Maybe is special in that it holds either a Just (with a non-empty value) or a Nothing (with no value at all).

You'd likely use a helper, like Maybe.from(..), to automatically create one or the other depending on the emptiness check.
Another thing you might want to do with a Maybe is to effectively use an `if` like conditional to either retrieve the non-empty value, or substitute some sort of default.

One way of doing that is with a monad behavior called Foldable.
Ex:

id = v => v;
function printGreeting(name) {
msg =
Maybe.from(name)
.map(n => `Hello, ${n}!!`)
.fold(
() => "Is that a ghost!?",
id
);
console.log(msg);
}

printGreeting("Kyle"); // Hello, Kyle!!
printGreeting(); // Is that a ghost!?
Let's break that down..

1. Maybe.from(..) checks a value to see if it's empty or non-empty, and creates either a Maybe:Just or Maybe:Nothing

2. .map(..) runs only for Maybe:Just but is skipped for a Maybe:Nothing; if it runs, it creates a new Maybe:Just holding the new greeting
3. .fold( fn1, fn2 ) runs fn1 in the case of Maybe:Nothing and runs fn2 in the case of Maybe:Just. In both cases, whatever those functions return just comes out directly (not wrapped in another monad).

4. Once we have `msg` as a string, we just console.log(..) it.
OK, interesting! We're already doing some cool stuff, with just a few of the most basic concepts of monads.

I hope *MAYBE* by now you're SLIGHTLY less nervous or confused by monads! ;-)
You can follow @getify.
Tip: mention @twtextapp on a Twitter thread with the keyword “unroll” to get a link to it.

Latest Threads Unrolled: