Basket Case

Pattern matching for JavaScript.
Guards
var match = require('basketcase'),
guard = match.guard;
describe('primitives', function(){
it('should recurse on factorial', function(){
var equal = guard.equal,
fn = match(
guard(equal(1, 0))(1),
function(x){return x*fn(x-1);});
eq(_.range(0, 7).map(fn), [1,1,2,6,24,120,720]);
});
it('should recurse on fibonacci', function(){
var equal = guard.equal,
fn = match(
guard(equal(0, 1))(),
function(x){return fn(x-1) + fn(x-2);});
eq(_.range(0, 11).map(fn), [0,1,1,2,3,5,8,13,21,34,55]);
});
});
Multi Methods
var match = require('basketcase'),
method = match.method,
guard = match.guard,
instanceOf = guard.instanceOf,
prototypeOf = guard.prototypeOf,
isA = guard.isA;
describe('Asteroid/Spaceship instanceOf', function(){
var Asteroid = function(id){
this.id = id;
};
Asteroid.prototype.crash = function(){
return " Boom! "+this.id;
};
var Spaceship = function(id){
this.id = id;
};
Spaceship.prototype.crash = function(){
return " Bang! "+this.id;
};
function rock(id){
return new Asteroid(id);
}
function ship(id){
return new Spaceship(id);
}
it('should overload crash guard method', function(){
var crash = match(
method(Asteroid, Asteroid)(rockRock),
method(Spaceship, Spaceship)(shipShip),
method(Asteroid, Spaceship)(rockShip),
method(Spaceship, Asteroid)(shipRock));
testCrash(crash, rock, ship);
});
it('should overload crash guard isA', function(){
var crash = match(
guard(isA(Asteroid), isA(Asteroid))(rockRock),
guard(isA(Spaceship), isA(Spaceship))(shipShip),
guard(isA(Asteroid), isA(Spaceship))(rockShip),
guard(isA(Spaceship), isA(Asteroid))(shipRock));
testCrash(crash, rock, ship);
});
});
function rockRock(a1, a2){
return 'Asteroids collide!'+a1.crash() + a2.crash();
}
function shipShip(s1, s2){
return 'Call the gecko...'+s1.crash()+s2.crash();
}
function rockShip(a, s){
return 'Space debris'+a.crash()+s.crash();
}
function shipRock(s, a){
return 'Whoops'+a.crash()+s.crash();
}
function testCrash(crash, rock, ship){
eq(crash(rock(1), rock(2)), 'Asteroids collide! Boom! 1 Boom! 2');
eq(crash(ship(1), ship(2)), 'Call the gecko... Bang! 1 Bang! 2');
eq(crash(rock(3), ship(3)), 'Space debris Boom! 3 Bang! 3');
eq(crash(ship(4), rock(4)), 'Whoops Boom! 4 Bang! 4');
}
var match = require('basketcase'),
caseOf = match.caseOf;
describe('caseOf regexp extracts', function(){
it('should extract regexp', function(){
var name = /(Mr|Mrs|Ms|Dr)\. ([A-Z][a-z]+) ([A-Z][a-z]+)/,
fn = caseOf(name)(function(title, first, last){
return [title, first, last];
});
eq(fn('Mr. Bob Hope'), ['Mr', 'Bob', 'Hope']);
eq(fn('Mrs. Jane Doe'), ['Mrs', 'Jane', 'Doe']);
eq(fn('Sir. Richard Branson'));
});
});
Algebraic Data Types
describe('caseclass Term Mul, Add', function(){
var Exp = data('Var(name) | Mul(a, b) | Add(a, b) | Div(a, b)'),
Var = Exp.Var,
Add = Exp.Add,
Div = Exp.Div,
Mul = Exp.Mul;
var simplify = match(
caseOf(Mul(Exp, 1), Add(Exp, 0), Div(Exp, 1))(function(a){
return simplify(a);
}),
caseOf(Mul(1, Exp), Add(0, Exp))(function(a, b){
return simplify(b);
}),
caseOf(Add(Number, Number))(function(a, b){
return a+b;
}),
caseOf(Mul(Number, Number))(function(a, b){
return a*b;
}),
caseOf(Add(Mul, Mul))(function(a, b){
if(_.isEqual(a.a, b.a)){
return simplify(Mul(a.a, simplify(Add(a.b, b.b))));
}
if(_.isEqual(a.b, b.b)){
return simplify(Mul(a.b, simplify(Add(a.a, b.a))));
}
}),
_.identity);
var termString = imply(simplify)(
caseOf(Var, Number)(),
caseOf(Div)(function(a, b){
return '('+termString(a)+' / '+termString(b)+')';
}),
caseOf(Mul)(function(a, b){
return '('+termString(a)+' * '+termString(b)+')';
}),
caseOf(Add)(function(a, b){
return '('+termString(a)+' + '+termString(b)+')';
}));
it('should print (a+b)*(c+d)', function(){
var t = Mul(Add(Var('a'), Var('b')), Add(Var('c'), Var('d')));
eq(termString(t), '((a + b) * (c + d))');
});
it('should simplify (a*b)+(a*c)', function(){
var t = Add(Mul(Var('a'), Var('b')), Mul(Var('a'), Var('c')));
eq(termString(t), '(a * (b + c))');
});
it('should simplify (2*c)+(3*c)', function(){
var t = Add(Mul(2, Var('c')), Mul(3, Var('c')));
eq(termString(t), '(c * 5)');
});
it('should calculate (2*4)+(3*4)', function(){
var t = Add(Mul(2, 4), Mul(3, 4));
eq(termString(t), 20);
});
it('should simplify 0+(c*1)+(a+0)/1', function(){
var t = Add(Add(0, Mul(Var('c'), 1)), Div(Add(Var('a'), 0), 1));
eq(termString(t), '(c + a)');
});
});