Let's first create a new object, and bind _ to
Pattern_Matching::variable for a little more sanity
var m = new Pattern_Matching ();
var _ = m.variable;
Doing some pattern matching is really easy, and looks pretty much like pattern matching in other languages.
A pattern can be anything : Object, Array, Number, String, Boolean, you
name it. In turn, any variable foo in a
pattern is denoted by Pattern_Matching::variable("foo") (here
written _("foo")
This means that matching {foo:"bar", bar:"baz"} with
{foo:_("quux")} will imply that you can access
quux in your callback function, and it will have a value of
"bar".
An few examples might be clearer...
function fact (n) {
return m.match(n,
[
[ 0 , function ( ) { return 1 }],
[ _("n"), function (a) { return (a.n * fact(a.n -1)) }]
]);
}
Factorial = 24
function go_deep(ob) {
return m.match(ob,
[
[{foo:{bar:{baz:'foo'}}, baz:_('b')}, function (a) { return a.b }],
[_('_') , function ( ) { return null }]
]);
}
Matched content :
{foo:{bar:{baz:'foo'}}, baz:'hello, world'} :
{foo:{foo:{baz:'foo'}}, baz:'hello, world'} :
var hd = function (l) {
return m.match(l,
[
[{Nil:_("_")} , function ( ) { throw "empty list" }],
[{Cons:[_("t"), _("_")]}, function (a) { return a.t }]
]);
}
var tl = function (l) {
return m.match(l,
[
[{Nil:_("_")} , function ( ) { throw "empty list" }],
[{Cons:[_("t"), _("q")]}, function (a) { return a.q }]
]);
}
var iter = function (f, l) {
return m.match(l,
[
[{Nil:_("_")} , function ( ) { }],
[{Cons:[_("t"), _("q")]}, function (a) { f(a.t); iter(f,a.q) }]
]);
}
var l = {Cons:[42, {Cons:[2, {Nil:null}]}]}