# raganwald-deprecated/homoiconic

Switch branches/tags
Nothing to show
Fetching contributors…
Cannot retrieve contributors at this time
223 lines (143 sloc) 9.98 KB

# Combinator Recipes for Working With Objects in JavaScript, Part I

(This post is Part I of II. The recipes in this post are excerpted the book JavaScript Allongé.)

### combinators

The word "combinator" has a precise technical meaning in mathematics:

"A combinator is a higher-order function that uses only function application and earlier defined combinators to define a result from its arguments."--Wikipedia

In this essay, we will be using a much looser definition of "combinator:" Pure functions that act on other functions to produce functions. If Objects are nouns and Methods are verbs, Combinators are the adverbs of programming.

If we were learning Combinatorial Logic, we'd start with the most basic combinators like `S`, `K`, and `I`, and work up from there to practical combinators. We'd learn that the fundamental combinators are named after birds following the example of Raymond Smullyan's famous book To Mock a Mockingbird.

There are an infinite number of combinators, but in this article we will focus on combinators that are useful when working with Plain Old JavaScript Objects ("POJOs") and with instances.

## Splat

In recent versions of JavaScript, arrays have a `.map` method. Map takes a function as an argument, and applies it to each of the elements of the array, then returns the results in another array. For example:

``````[1, 2, 3, 4, 5].map(function (n) {
return n*n
})
//=> [1, 4, 9, 16, 25]
``````

We say that `.map` maps its arguments over the receiver array's elements. Or if you prefer, that it defines a mapping between its receiver and its result. Libraries like Underscore provide a map function. It usually works like this:

``````_.map([1, 2, 3, 4, 5], function (n) {
return n*n
})
//=> [1, 4, 9, 16, 25]
``````

Why provide a map function? well, JavaScript is an evolving language, and when you're writing code that runs in a web browser, you may want to support browsers using older versions of JavaScript that didn't provide the `.map` function. One way to do that is to "shim" the map method into the Array class, the other way is to use a map function. Most library implementations of map will default to the `.map` method if its available.

This recipe isn't for `map`: It's for `splat`, a function that wraps around `map` and turns any other function into a mapping. In concept, `splat` is very simple:

``````function splat (fn) {
return function (list) {
return Array.prototype.map.call(list, fn)
}
}
``````

Here's the above code written using `splat`:

``````var squareMap = splat(function (n) {
return n*n
});

squareMap([1, 2, 3, 4, 5])
//=> [1, 4, 9, 16, 25]
``````

If we didn't use `splat`, we'd have written something like this

``````var squareMap = function (array) {
return _.map(array, function (n) {
return n*n
})
};
``````

Functional programming wonks will explain that something called partial functional application would be handy here. If JavaScript had it. Which it doesn't. Oh well.

And we'd do that every time we wanted to construct a method that maps an array to some result. `splat` is a very convenient abstraction for a very common pattern.

(`splat` was suggested by ludicast)

## Get

`get` is a very simple function. It takes the name of a property and returns a function that gets that property from an object:

``````function get (attr) {
return function (object) { return object[attr]; }
}
``````

You can use it like this:

``````var inventory = {
apples: 0,
oranges 144,
eggs: 36
};

get('oranges')(inventory)
//=> 144
``````

This isn't much of a recipe yet. But let's combine it with `splat`:

``````var inventories = [
{ apples: 0, oranges: 144, eggs: 36 },
{ apples: 240, oranges: 54, eggs: 12 },
{ apples: 24, oranges: 12, eggs: 42 }
];

splat(get('oranges'))(inventories)
//=> [ 144, 54, 12 ]
``````

That's nicer than writing things out "longhand:"

``````splat(function (inventory) { return inventory.oranges })(inventories)
//=> [ 144, 54, 12 ]
``````

Ruby users recognize `get`, it's equivalent to `Symbol#to_proc`, the method that allows them to write `inventory.map &:oranges` instead of using a block.

## Pluck

This pattern of combining `splat` and `get` is very frequent in JavaScript code. So much so, that we can take it up another level:

``````function pluck (attr) {
return splat(get(attr))
}

pluck('eggs')(inventories)
//=> [ 36, 12, 42 ]
``````

Libraries like Underscore provide `pluck` in a different form:

``````_.pluck(inventories, 'eggs')
//=> [ 36, 12, 42 ]
``````

Our recipe is terser when you want to name a function:

``````var eggsByStore = pluck('eggs');
``````

vs.

``````function eggsByStore (inventories) {
return _.pluck(inventories, 'eggs')
}
``````

## Maybe

A common problem in programming is checking for `null` or `undefined` (hereafter called "nothing," while all other values including `0`, `[]` and `false` will be called "something"). Languages like JavaScript do not strongly enforce the notion that a particular variable or particular property be something, so programs are often written to account for values that may be nothing.

This recipe concerns pattern that is very common: A function `fn` takes a value as a parameter, and its behaviour by design is to do nothing if the parameter is nothing:

``````function isSomething (value) {
return value != null
}

function checksForSomething (value) {
if (isSomething(value)) {
// function's true logic
}
}
``````

Alternately, the function may be intended to work with any value, but the code calling the function wishes to emulate the behaviour of doing nothing by design when given nothing:

``````var something = isSomething(value) ?
doesntCheckForSomething(value) : value;
``````

Naturally, there's a recipe for that, borrowed from Haskell's maybe monad, Ruby's andand, and CoffeeScript's existential method invocation:

``````function maybe (fn) {
return function () {
var i;

if (arguments.length === 0) {
return
}
else {
for (i = 0; i < arguments.length; ++i) {
if (arguments[i] == null) return arguments[i]
}
return fn.apply(this, arguments)
}
}
}
``````

`maybe` reduces the logic of checking for nothing to a function call, either:

``````function checksForSomething = maybe(function (value) {
// function's true logic
});
``````

Or:

``````var something = maybe(doesntCheckForSomething)(value);
``````

Now let's look an an elegant use for `maybe`. You recall `get` from above? `get('name')` acts like `function (obj) { return obj.name }` You can use `get` with `.map`: `arrayOfObjects.map(get('name'))` or with `splat`: `splat(get('name))(arrayOfObjects)`. Now consider: What if `arrayOfObjects` is a sparse array? If some of its entries are `null`?

`maybe` to the rescue:

``````arrayOfObjects.map(maybe(get('name')))
``````

This maps the array, getting the name if there is a value.

## Summary of Part I

• We've seen four handy combinators: "get," "splat," "pluck," and "maybe."
• "Get" and "maybe" play well together; "splat" and "pluck" are conveniences that help program in a functional rather than OO style.

In Part II, we'll look at a more complex recipe, "partial," and some combinators that are specifically tuned for working with instance methods: "bound," "send," and "fluent." (cough). The recipes in this post are from the book JavaScript Allongé, a book focused on working with functions in JavaScript, including combinators, constructors, methods, and decorators. You can download a free sample PDF.

Feedback welcome, or discuss these ideas on reddit and hacker news.

My recent work:

(Spot a bug or a spelling mistake? This is a Github repo, fork it and send me a pull request!)