Fun.js – Bilby.js
I’ve written a book entitled Functional JavaScript due out in print sometime in June 2013. In the book I introduce and explore various techniques for writing code in a functional style using the Underscore library. As much as I would have loved to delve into the ecosystem of functional JS libraries, I didn’t want to distract from the core functional topics in the book.1 Therefore, I present a series to explore a few of my favorite functional JavaScript libraries2 focusing primarily on the feature(s) that make them interesting, innovative or unique.3
Bilby
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.4 Brian touts his use of category theory in Bilby, but that’s a red herring that detracts from its powerful, yet simple, capabilities and ideas.
For example, with Bilby is 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 noAnimals = 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 arguments5
- An action function that performs the method behaviors
The Environment#method
takes the three arguments listed above and returns a new environment:
var cats = noAnimals.method('speak', isA('cat'), say("mew"));
As shown, adorning an environment with a new multimethod returns a new environment. I can now call speak
:
cats.speak({type: 'cat'}); // (console) The cat says mew
Adding a new polymorphic behavior is simple:
var catsNDogs = cats.method('speak', isA('dog'), say("woof"));
And calling speak
with a dog object works as expected:
catsNDogs.speak({type: 'dog'}); // (console) The dog says woof
And cats still sound like cats:
catsNDogs.speak({type: 'cat'}); // (console) The cat says mew
Of course, I can match on an arbitrary condition within the dispatch predicate:
var animals = catsNDogs.method('speak', function(obj) { return isA('frog')(obj) && (obj.status == 'dead'); }, say('Hello ma, baby!'));
So passing in a dead frog works all the same:
animals.speak({type: 'frog', status: 'dead'}); // (console) The frog says Hello ma, baby!
I love the idea of the immutable environments and look forward to the chance to take advantage of them for a project. Of course, Bilby provides more than multimethods, including a trampoline that allows you to return functions, monadic structures,6, a crazy-insane operator overloading form, validation helpers and much more.
If you want to talk functional programming, my book, the library in question or anything else then feel free to comment below or email me at the address at the top of this blog post.
:F
-
I cover a few in an appendix, but did not go as deeply as I would have liked given unlimited time and page count. ↩
-
Including, but not limited to: Functional JavaScript by Oliver Steele, Lemonad, RxJS, Bilby, Allong.es, D3, Reducers, Underscore-contrib, Mori and Bacon.js. ↩
-
Seriously, who needs yet another blog post on closures,
map
,reduce
,filter
,__proto__
and the like? I’ll hit on those topics from time to time, but they will not be the focus of these posts. ↩ -
Bilby’s multimethods are similar to the
dispatch
function defined in chapter 5 of Functional JavaScript but more robust and flexible. ↩ -
The
isA
function is an example of a curried function, up to 2 parameters. A curried function is one that returns a closure for each of its logical arguments minus one. When it gets the last argument the function is executed with all of the historical arguments given to it. All talk more about curried functions in the future, but the key is that this behavior is very different than partial application such as provided by_.partial
orFunction#bind
. ↩ -
Bilby is not currently Fantasy Land compatible, but should be soon(ish). I hope to write about FL in the near(ish) future. ↩
No Comments, Comment or Ping
Reply to “Fun.js – Bilby.js”