Skip to content

Instantly share code, notes, and snippets.

@ianchanning
Last active March 12, 2018 08:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ianchanning/9745c48581e193e13ae5b78da4d8a87f to your computer and use it in GitHub Desktop.
Save ianchanning/9745c48581e193e13ae5b78da4d8a87f to your computer and use it in GitHub Desktop.
Yet another monad explanation

tl;dr Here's a really short explanation for JavaScript, as in just the flatmap part.

map is pretty well understood in JavaScript (and I'm assuming you understand it).

So you 'just' need to make the leap to flatmap. Which is mapping something and flattening the result.

Flattening a JavaScript array is concatenating a 2D array into an array.

Longer Python example

Another attempt at explaining monads, using just Python lists and the map function. I fully accept this isn't a full explanation, but I hope it gets at the core concepts.

I got the basis of this from a funfunfunction video on Monads and the Learn You A Haskell chapter 'For a Few Monads More'. I highly recommend watching the funfunfunction video.

At it's very simplest, Monads are objects that have a map and flatMap functions (bind in Haskell). There are some extra required properties, but these are the core ones.

flatMap 'flattens' the output of map, for lists this just concatenates the values of the list e.g.

concat([[1], [4], [9]]) = [1, 4, 9]

So in Python we can very basically implement a list Monad with just these two functions:

# helper function as python doesn't have concat
def concat(lst):
    return sum(lst, [])

# monad magic
def flatMap(func, lst):
    return concat(map(func, lst))

func is any function that takes a value and returns a list e.g.

lambda x: [x*x]

Explanation

For clarity I created the concat method in Python via a simple function, which sums the lists i.e. [] + [1] + [4] + [9] = [1, 4, 9] (Haskell has a native concat method).

I'm assuming you know what the map function is e.g.:

>>> list(map(lambda x: [x*x], [1,2,3]))
[[1], [4], [9]]

Flattening is the key concept of Monads and for each object which is a Monad this flattening allows you to get at the value that is wrapped in the Monad.

Now we can call:

>>> flatMap(lambda x: [x*x], [1,2,3])
[1, 4, 9]

This lambda is taking a value x and putting it into a list. A monad works with any function that goes from a value to a type of the monad, so a list in this case.

That's your list monad defined.

You can now compare this to a python list comprehension:

>>> [x*x for x in [1,2,3]]
[1, 4, 9]

More explanation, time to bring out the Haskell

Other examples that aren't lists are JavaScript Promises, which have the then method and JavaScript Streams which have a flatMap method.

So Promises and Streams use a slightly different function which flattens out a Stream or a Promise and returns the value from within.

The Haskell list monad has the following definition:

instance Monad [] where  
    return x = [x]  
    xs >>= f = concat (map f xs)  
    fail _ = [] 

i.e. there are three functions return (not to be confused with return in most other languages), >>= (the flatMap) and fail.

Hopefully you can see the similarity between:

xs >>= f = concat (map f xs)

and:

def flatMap(f, xs):
    return concat(map(f, xs))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment