Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save peterschussheim/6dd847a2da56e05304686c1cfd69b547 to your computer and use it in GitHub Desktop.
Save peterschussheim/6dd847a2da56e05304686c1cfd69b547 to your computer and use it in GitHub Desktop.
Simple Algebraic data types in JavaScript, see https://github.com/fantasyland/fantasy-land
/**
* Identity
*/
var Identity = function(val) {
this.val = val;
};
Identity.prototype.map = function(fn) { // Functor
return Identity.of(fn(this.val));
};
Identity.prototype.ap = function(app) { // Apply
return app.map(this.val);
};
Identity.prototype.chain = function(fn) { // Chain
return fn(this.val);
};
Identity.of = function(val) { // Applicative
return new Identity(val);
};
/**
* Const
*/
var Const = function(val) {
this.val = val;
};
Const.prototype.map = function(fn) { // Functor
return Const.of(this.val);
};
Const.prototype.ap = function(app) { // Apply
return Const.of(app);
};
Const.of = function(val) { // Applicative
return new Const(val);
};
/**
* Maybe
*/
var Maybe = function(val) {
this.val = val;
};
Maybe.prototype.isNothing = function() {
return this.val === null || this.val === undefined;
};
Maybe.prototype.map = function(fn) { // Functor
return this.isNothing() ? Maybe.of(null) : Maybe.of(fn(this.val));
};
Maybe.prototype.ap = function(app) { // Apply
return (typeof this.val !== 'function') ? Maybe.of(null) : app.map(this.val);
};
Maybe.of = function(val) { // Applicative
return new Maybe(val);
};
/**
* Either
*/
var Either = (function() {
var Either = function(left, right) {
if (arguments.length === 1) {
return function(right) {
return right == null ? Either.Left(left) : Either.Right(right);
};
}
return right == null ? Either.Left(left) : Either.Right(right);
}
Either.prototype.map = function() { // Functor
return this;
};
Either.of = function(val) { // Applicative
return Either.Right(val);
};
Either.Left = function(val) {
return new _Left(val);
};
Either.Right = function(val) {
return new _Right(val);
};
var _Right = function(val) {
this.val = val;
}
_Right.prototype = Object.create(Either.prototype);
_Right.prototype.map = function(fn) { // Functor
return new _Right(fn(this.val));
};
_Right.prototype.ap = function(app) { // Apply
return app.map(this.val);
};
var _Left = function(val) {
this.val = val;
}
_Left.prototype = Object.create(Either.prototype);
_Left.prototype.ap = function(app) { // Apply
return app;
};
return Either;
}());
/**
* Array
*/
Array.prototype.map; // Functor
Array.prototype.concat; // Semigroup
Array.prototype.ap = function(app) { // Apply
return this.map(fn => app.map(fn));
};
Array.of = function(val) { // Applicative
return [val];
};
/**
* Function
*/
Function.prototype.map = function(fn) { // Functor
return function(val) {
return fn(this(val));
}.bind(this);
};
/**
* Tree
*/
var Tree = function(val) {
this.val = val;
};
Tree.prototype.map = function(fn) { // Functor
var walk = function(i) {
if (Array.isArray(i)) {
return i.map(walk);
}
return fn(i);
};
return Tree.of(walk(this.val));
};
Tree.prototype.ap = function(app) { // Apply
return this.map(fn => app.map(fn));
};
Tree.of = function(val) { // Applicative
return new Tree(val);
};
/**
* IO
*/
var IO = function(fn) {
this.val = fn;
};
IO.prototype.runIO = function() {
return this.val.apply(this, arguments);
};
IO.prototype.map = function(fn) { // Functor
return IO.of(R.compose(fn, this.val));
};
IO.of = function(val) { // Applicative
return new IO(function() {
return val;
});
};
// Identity
R.map(R.add(1), Identity.of(2)); //=> Identity(3)
R.ap(Identity.of(R.add(5)), Identity.of(50)); //=> Identity(55)
// Const
R.map(R.add(1), Const.of(2)); //=> Const(2)
R.ap(Identity.of(R.add(5)), Const.of(50)); //=> Const(50)
// Maybe
R.map(R.add(1), Maybe.of(2)); //=> Maybe(3)
R.map(R.add(1), Maybe.of(null)); //=> Maybe(null)
R.ap(Maybe.of(R.add(5)), Maybe.of(50)); //=> Maybe(55)
R.ap(Maybe.of(R.add(5)), Maybe.of(null)); //=> Maybe(null)
R.ap(Maybe.of(null), Maybe.of(50)); //=> Maybe(null)
// Either
R.map(R.add(1), Either('err', 3)); //=> Right(4)
R.map(R.add(1), Either('err', null)); //=> Left('err')
R.map(R.add(1), Either.Right(5)); //=> Right(6)
R.map(R.add(1), Either.Left('err')); //=> Left('err')
R.ap(Identity.of(R.add(1)), Either('err', 7)); //=> Right(8)
R.ap(Identity.of(R.add(1)), Either('err', null)); //=> Left('err')
R.ap(Identity.of(R.add(1)), Either.Right(8)); //=> Right(9)
R.ap(Identity.of(R.add(1)), Either.Left('err')); //=> Left('err')
R.ap(Either('err2', R.add(1)), Identity.of(2)); //=> Right(3)
R.ap(Either('err2', null), Identity.of(2)); //=> Right(2)
R.ap(Either.Right(R.add(2)), Identity.of(4)); //=> Right(6)
R.ap(Either.Left('err2'), Identity.of(8)); //=> Right(8)
// Array
R.map(R.add(1), [2, 4, 6]); //=> [3, 5, 7]
R.ap([R.add(3), R.add(5)], Identity.of(50)); //=> [Identity(53), Identity(55)]
// Function
var formula = R.map(multiply(2), add(1)); //=> (Number -> Number)
R.map(formula, Identity.of(3)); //=> Identity(8)
// Tree
R.map(R.add(100), Tree.of([1, 3, [5, [7]], 13])); //=> Tree([101, 103, [105, [107]], 113])
R.ap(Identity.of(R.add(200)), Tree.of([1, 3, [5, [7]], 13])); //=> Tree([201, 203, [205, [207]], 213])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment