Appendix A. Functional JavaScript in the Wild

In no way does this book represent even a modicum of original thinking regarding functional programming in JavaScript. For many years—indeed, for as long as JavaScript has existed—people have pushed the boundaries of its support for a functional style. In this appendix, I’ll attempt to briefly summarize what I perceive as a fair sampling of the offerings in languages and libraries on the topic of functional JavaScript. No ranking is implied.

Functional Libraries for JavaScript

There are numerous noteworthy JavaScript libraries available in the wild. I’ll run through the high-level features of a few herein and provide a few examples along the way.

Functional JavaScript

Oliver Steele’s Functional JavaScript library is the first functional library that I discovered. It provides all of the normal higher-order functions like map, but it provides a very interesting string-based short-form function format. That is, to square the numbers in an array, one would normally write the following:

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

However, with the Functional JavaScript function literal string, the same code be written as:

map('n*n', [1, 2, 3, 4]);
//=> [2, 4, 9, 16]

Functional JavaScript also provides currying of the function literal strings:

var lessThan5 = rcurry('<', 5);

lessThan5(4);
//=> true

lessThan5(44);
//=> false

Functional JavaScript is a masterful piece of JavaScript metaprogramming and well worth exploring for its technical insights.

Underscore-contrib

A long time ago (in Internet years) I wrote a functional JavaScript library named Doris heavily inspired by Steele’s Functional JavaScript and the Clojure programming language. I used Doris for some internal libraries but eventually deprecated it in favor of Underscore and (when possible) ClojureScript. When writing this book, I resurrected the Doris source code, ported it to Underscore, cleaned up the code, and renamed it Lemonad (pronounced lemonade), then moved most of the capabilities into the official Underscore-contrib library.

Underscore-contrib is built on Underscore and provides dozens of useful applicative, higher-order and monadic functions. When importing Underscore-contrib, the functions are mixed into the Underscore _ object, allowing you to turn Underscore up to 11. In addition to the core functionality, I’ve implemented a number of “extras” for Underscore-contrib, including the following:

Codd

A relational algebra library

Friebyrd

A library providing an embedded logic system

Minker

A library providing an embedded datalog

var a = ['a','a','b','a'];
var m = _.explode("mississippi");

_.frequencies(a)
//=> {a: 3, b: 1}

_.frequencies(m)
//=> {p: 2, s: 4, i: 4, m: 1}

There are many more functions available. Fortunately, most of the functions defined in this book are available in Lemonad or Underscore-contrib, so consider this the unofficial manual.

RxJS

Microsoft’s Reactive Extensions for JavaScript (RxJS) is a set of libraries that facilitate asynchronous, event-driven programming models. RxJS works against an Observable abstraction that allows you to process asynchronous data streams via a rich, LINQ-like functional query model.

When I was a younger man (this of course dates me) I spent a seemingly limitless amount of time playing my old Nintendo NES system. The Japanese company Konami created many interesting games, but prime among them was my favorite, Contra. The goal of Contra was…well, no one cares anymore, but one interesting point was that there was a cheat code that you could enter to get 30 extra lives. The cheat code is described as follows:

var codes = [
    38, // up
    38, // up
    40, // down
    40, // down
    37, // left
    39, // right
    37, // left
    39, // right
    66, // b
    65  // a
];

The cheat code was entered via the game controller before the game started, and it was the only reason that I ever completed the game. If you want to add the Konami Code (as it’s commonly called) to a web page, then you can do so with RxJS. A useful method to compare a sequence of values with RxJS is called sequenceEqual, and can be used to check that a stream of integers matches the Konami Code:

function isKonamiCode(seq) {
  return seq.sequenceEqual(codes);
}

RxJS allows you to tap into many sources of asynchronous events, including a page document’s key presses, as shown:

var keyPressStream = $(document).keyupAsObservable()
  .select(function (e) { return e.keyCode })
  .windowWithCount(10, 10);

The keyPressStream represents a stream of keycodes built from keypress events. Rather than observing on every keypress, RxJS allows you to chunk the stream into aggregate segments using the windowWithCount method. One additional point is that RxJS adorns jQuery itself with relevant Observable creating methods, and will do the same for various other JavaScript frameworks. This seamless integration with existing libraries is a pleasure to work with.

Now that I have a stream of keycodes, I can declaratively tell RxJS what I would like to do with them:

keyPressStream
  .selectMany(isKonamiCode)
  .where(_.identity)
  .subscribe(function () {
    alert("You now have thirty lives!");
  });

Of note is that the where method could transform the data values along the way, but I chose to pass them through using Underscore’s _.identity function. The function given to the select method is what will run whenever the function assigned via the selectMany returns a truthy value. If I were to load the preceding code into a web page and push the correct sequence of arrow keys followed by the characters “a” and “b,” then an alert box would launch.

RxJS is an amazing library that provides a way to capture asynchronous flow as a value—a truly mind-bending paradigm.

Bilby

If Lemonad turns Underscore up to 11, then Bilby turns Lemonad up to 12 or beyond. A self-contained functional library, Brian McKenna’s Bilby stretches the possibilities of functional style in JavaScript. It’s worth exploring Bilby to learn its entire feature set, but one that is particularly nice is its implementation of multimethods.

Bilby’s multimethods are similar to the dispatch function defined in Chapter 5 but more robust and flexible. Using Bilby, you can define functions that dispatch on any number of interesting conditions. Bilby provides a module system called environments that aggregate related methods and properties:

var animals = bilby.environment();

Before adding a multimethod I can define a few helper functions:

function voice(type, sound) {
  return ["The", type, "says", sound].join(' ');
}

function isA(thing) {
  return function(obj) {
    return obj.type == thing;
  }
}

function say(sound) {
  return function(obj) {
    console.log(voice(obj.type, sound));
  }
}

Using these helpers I can tell Bilby:

  • The name of the method

  • A predicate that checks the arguments

  • An action function that performs the method behaviors

The Environment#method takes the three arguments just listed:

var animals = animals.method('speak', isA('cat'), say("mew"));

As shown, adorning an environment with a new multimethod returns a new environment. I can now call speak:

animals.speak({type: 'cat'});
// The cat says mew

Adding a new polymorphic behavior is simple:

var animals = animals.method('speak', isA('dog'), say("woof"));

And calling speak with a dog object works as expected:

animals.speak({type: 'cat'});
// The cat says mew

animals.speak({type: 'dog'});
// The dog says woof

Of course, I can match an arbitrary condition within the dispatch predicate:

var animals = animals.method('speak',
  function(obj) {
    return (isA('frog')(obj) && (obj.status == 'dead'))
  },
  say('Hello ma, baby!'));

So passing in a dead frog works the same:

animals.speak({type: 'frog', status: 'dead'});
// The frog says Hello ma, baby!

Bilby provides much more than multimethods, including a trampoline that allows you to return functions, monadic structures, validation helpers, and much more.

allong.es

Reginald Braithwaite’s allong.es library has a bevy of useful function combinators in its arsenal. However, an interesting aspect from my perspective (and something that I didn’t cover in depth) is its support for stateful iterators:

var iterators = require('./allong.es').iterators
var take = iterators.take,
    map = iterators.map,
    drop = iterators.drop;

var ints = iterators.numbers();

Aside from the necessary import seance required to get the correct allong.es iteration functions, I also defined an iterator, ints, over all numbers. I can then “perform” some operations over the ints iterator:

var squares = take(drop(map(ints, function(n) {
  return n * n;
}), 100000), 100);

Just for fun, I squared all of the integers, dropped the first 100,000 results, then grabbed the next 100. The magic of the allong.es iterator is that I’ve not actually performed any calculation yet. Only when I query the iterator using an external iterator (in my case, for) will any of the calculations occur:

var coll = [];
for (var i = 0; i < 100; i++ ) {
  coll.push(squares())
}

coll;
//=> [10000200001,
//    10000400004,
//    10000600009,
//    10000800016,
//    10001000025,
//    10001200036,
//    ...
//    10020010000]

I can check the math by manually squaring the number 100,001 (because I dropped 100,000, recall):

100001 * 100001
//=> 10000200001

And, as shown, the manual calculation matches with the first element in the coll array. There is too much in allong.es (and about iterators in general) to do justice here. I highly recommend you explore.

Other Functional Libraries

There are a growing number of JavaScript libraries supporting varying degrees of functional programming. The grandmaster of them all—jQuery—has always been somewhat functional, but with the inclusion of promises has gotten more so. A nice project that I’ve followed since its inception is Reducers, which implements a generalized reducible collections API inspired by Clojure’s reducer functionality. The Lo-Dash project is a major fork of Underscore that attempts a cleaner core and more performance. The Mori project by David Nolen is a facade over the ClojureScript core library, including its persistent data structures. The Udon library is a very straightforward functional library akin to Lemonad. Finally, the prelude.ls project is also a straightforward functional affair. However, where prelude.ls differs is that it’s originally written in the statically typed language TypeScript and compiled to JavaScript.

Functional Programming Languages Targeting JavaScript

When a functional library simple doesn’t cut it, more and more programmers are turning to new languages using JavaScript as their compilation target. I’ll outline just a few of the languages that I’m familiar with (to varying degrees herein). Don’t take a language’s inclusion as an endorsement and don’t take a language’s exclusion as a rejection. Included are only the handful that I’ve either used on real projects, contributed to in some way, or studied in my spare time.

ClojureScript

The ClojureScript programming language is a variant of Clojure that compiles down to JavaScript. It has many of the same features as Clojure, including but not limited to the following:

  • Persistent data structures

  • Reference types

  • Namespaces

  • Strong JavaScript interop

  • Laziness

  • Destructuring assignment

  • Protocols, types, and records

A taste of ClojureScript is as follows:

(defn hi [name]
  (.log js/console (str "Hello " name "!")))

(hi "ClojureScript")

;; (console) Hello ClojureScript

ClojureScript is an exciting language targeting the large-scale JavaScript application space. Indeed, I’ve used it to great effect in building robust single-page applications with the Pedestal web framework.[105] You can find out more about ClojureScript in the second edition of my other book, The Joy of Clojure.

CoffeeScript

CoffeeScript is a popular programming language that is the very embodiment of “JavaScript: The Good Parts” with a very clean syntax. The “hello world” example is simply trivial:

hi = (name) ->
  console.log ['Hello ', name, '!'].join ''

hi 'CoffeeScript'

# (console) Hello CoffeeScript

Some of the additional features above JavaScript include:

  • Literate programming support (something I love a lot)

  • Varargs

  • List comprehensions

  • Destructuring assignment

Its level of support for functional programming is effectively that of JavaScript, but its balance of features and syntax can act to make a functional style much cleaner.

Roy

Roy is a statically typed functional programming language inspired by ML in the early stages of its life. While Roy provides many of the features common to ML-family languages including pattern matching, structural types, and tagged unions, its type system is most interesting to me. If I implement a hi function that attempts to concatenate strings s in JavaScript, then I’m set for a rude surprise:

let hi name: String =
  alert "Hello " + name + "!"

// Error: Type error: String is not Number

Roy reserves the + operator for mathematical operations, disallowing the concatenation overload. However, Roy provides a ++ operator that will suffice:

let hi name: String =
  console.log "Hello " ++ name ++ "!"

And calling the hi function is as simple as this:

hi "Roy"

// Hello Roy!

I, for one, will follow Roy’s progress and hope to see good things come from it.

Elm

Like Roy, Elm is a statically typed language that compiles down to JavaScript. Also like Roy, Elm will not allow willy-nilly string concatenation using +, as shown here:

hi name = plainText ("Hello " + name + "!")

-- Type error (Line 1, Column 11):
-- String is not a {Float,Int}
-- In context: + "Hello "

Once again, like Roy, Elm reserves the ++ function for such use:

hi name = plainText ("Hello " ++ name ++ "!")

main = hi "Elm"

-- (page text) Hello Elm!

However, where Elm really departs from Roy is that instead of merely being a programming language, it truly is a system for development. That is, Elm provides a language centered around the Functional Reactive Programming (FRP) paradigm. In a nutshell, FRP integrates a time model with an event system for the purposes of sanely building robust systems centered on system-wide change effects. I could never adequately cover FRP in these pages, as it could in fact, fill its own book. If you’re looking to stretch your mind, then Elm is a nice system for just such an exercise.



[105] And its predecessor. Pedestal is at http://pedestal.io/.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.176.5