Improving your functional CoffeeScript and JavaScript

Lately I have found myself being influenced by functional programming languages like Haskell and Clojure, especially in how I write JavaScript. Despite it still being a bit verbose, I think functional JavaScript can be very elegant. Add CoffeeScript to the mix and it’s looks even better.

More importantly, I find that code written in a functional style is much simpler than imperative code. It is easier to test, reuse and rewrite. So how do you do this in JavaScript?

One way to get started is to use something like Underscore.js and convert those good ol’ for loops to compositions of higher-order functions. I think the following example, although rather simple, shows how functional style code can be much easier to read and understand.

var persons = [
    {
        name: 'Lisa',
        age: 19,
        city: 'Stockholm'
    },
    ...
];

// Imperative style
var adultsByCity = {};
for (var i = 0; i < persons.length; i++) {
    var p = persons[i];
    if (p.age >= 18) {
        if (adultsByCity[p.city] === undefined) {
            adultsByCity[p.city] = [];
        }
        adultsByCity[p.city].push(p);
    }
}

// Functional style using Underscore.js
var adultsByCity = _(persons)
    .chain()
    .filter(function (p) { return p.age >= 18; })
    .groupBy('city')
    .value();

If you are not used to this style of writing and want to learn more, I would recommend studying a functional language like Haskell or Clojure where higher-order functions are pretty much the bread and butter.

Trying to improve my functional JavaScript and CoffeeScript I started looking at monads. I really like Haskell’s do notation so I thought that I could try implementing my own version in CoffeeScript. The goal is both to implement a do notation and to write the implementation itself in a functional style. The following is my attempt at doing so.

So, what’s a monad?

I’d like to point out that this is not a monad tutorial. There are vast amounts of tutorials on monads already, and I will try not to contribute to the monad tutorial fallacy. However, I think that some kind of summary is needed for the purposes of this post.

“In functional programming, a monad is a structure that represents computations defined as sequences of steps.”

Monad (functional programming), Wikipedia

The core functions of a monad is return (also called unit) and bind (>>= in Haskell).

  • return takes a non-monadic value and returns a monadic value.
  • bind takes a monadic value and a function which is applied to the non-monadic value.

In Haskell, these are defined as follows. Note that this is not the actual Monad typeclass.

class Monad m where
    return :: a -> m a
    (>>=) :: m a -> (a -> m b) -> m b

In other words, a monad defines how monadic values are constructed and how a computation is applied to those values.

Monad Definitions

To represent the monad I use a simple JavaScript object containing the return and bind functions.

Maybe

I use two container types for the Maybe monad – Nothing and Just.

class Nothing
    constructor: () ->

class Just
    constructor: (@value) ->

… along with these convenience functions.

nothing = new Nothing
just = (x) -> new Just x

The definitions looks like this.

Maybe =
    return: (x) -> just x
    bind: (x, f) ->
        if x instanceof Nothing then return x
        if x instanceof Just then return (f x.value)
        throw "#{x} is not an instance of the Maybe monad"

Given this definition, I can bind computations to monadic values as follows.

maybeFive = Maybe.return 5
maybePlusTwo = (x) -> Maybe.return (x + 2)
maybeSeven = Maybe.bind maybeFive, maybePlusTwo
Maybe.bind maybeSeven, console.log

Promise

Using the excellent Q library, the Promise monad is even simpler to define.

Promise =
    return: Q
    bind: (x, f) -> x.then f

Using the underlying promise functions of Q is more straight forward than using the monad, but we will need the abstraction later on.

Implementing the do notation

Haskell’s do notation supports a number of forms. To keep my version simple, I decided to implement only the <- binding. <- takes a monadic value and binds the non-monadic value to the given symbol. In Haskell, the following expressions are equivalent.

do
    five <- maybeFive
    two <- maybeTwo
    return $ five + two

maybeFive >>= five -> maybeTwo >>= two -> return $ five + two

The steps of the do expression is translated into a chain of monad bind operations.

To mimic this in CoffeeScript, I need some way for computations to refer to the non-monadic values of preceding computations (e.g. for the last computation in the Haskell example to refer to five and two). The best thing I’ve come up with so far is recursively building a scope object to which the computation functions are bound. This enables each computation to refer to non-monadic values through this.

# Converts an array of values to an array of pairs (arrays).
toPairs = (xs) -> if !xs or xs.length < 2 then [] else [xs[0..1]].concat (toPairs xs[2..])

# Recursively applies all computations and builds a scope with their resulting
# non-monadic values. Returns the (optionally monadic) value of the last line.
M.do = (monad, computations...) ->
    applyWithScope = (cps, scope) ->
        if cps.length >= 1
            [[key, value], rest...] = cps
            result = if typeof value is 'function' then value.bind(scope)() else value

            # If its the last computation just return the possibly monadic value.
            if _(rest).isEmpty() then result
            else
                try
                    monad.bind result, (r) ->
                        resultScope = _.object [key], [r]
                        # Recursively apply the rest of the computations with the new scope.
                        applyWithScope rest, _.extend(scope, resultScope)
                catch e
                    throw new Error("Exception at do expression that binds to #{key}: #{e}")

    applyWithScope (toPairs computations), {}

Actually, I started out with a single scope object which was mutated in each recursion. I even used indices in the recursive function calls. In short, an ugly mess!

Later on when looking back at the implementation I realized I should create new scope objects and get rid of the indices. It is really just a fold of the computations, although slightly more complex because of bind.

Trying it out with Maybe

M.do Maybe,
    # A computation is a function that returns a monadic value.
    'a', () -> Maybe.return 4
    # It can also be just a monadic value.
    'b', Maybe.return 6
    # Computations can refer to the results of previous ones through
    # this. The last computation does not have to return a monadic
    # value.
    '_', () -> console.log (this.a + this.b)

The equivalent code in JavaScript does not look too bad.

M.do(Maybe,
    'a', function() {
        return Maybe.return(4);
    },
    'b', Maybe.return(6),
    '_', function() {
        return console.log(this.a + this.b);
    });

Promises in action

This is a bit more interesting example using promises.

getUser = (id) -> ... # Returns a promise of a user
loggedInUser = ... # A user
getFriendsOf = (user) -> ... # Returns a promise of an array of users

M.do Promise,
    'somePerson', () -> getUser 'some.person'
    'mine', () -> getFriendsOf loggedInUser
    'persons', () -> getFriendsOf this.somePerson
    '_', () ->
        inCommon = _.intersection this.mine, this.persons
        asString = inCommon.join ', '
        console.log "#{inCommon.length} friends in common: #{asString}."

Summary

Writing the do notation in CoffeeScript was very fun! For me this was also a great way to learn more about CoffeeScript as well as monads. Even if I’ll never write anything useful in Haskell itself I am sure it will remain a great source of inspiration for writing functional JavaScript and CoffeeScript.

If you are interested in functional JavaScript, give Haskell or Clojure a try, and see where it takes you. It’s a great learning experience, and a lot of fun!

This Post Has 2 Comments

  1. Christian

    Nice post! Do you have any good resources for learning more about monads?

    1. Oskar Wickström

      Thank you Christian! The online book Learn You a Haskell for Great Good has a thorough chapter on monads. It has helped me a lot and I think the book is great for learning functional programming, even if you’re not using Haskell.

Leave a Reply