peterschussheim
11/9/2016 - 3:37 PM

Simple Algebraic data types in JavaScript, see https://github.com/fantasyland/fantasy-land

Simple Algebraic data types in JavaScript, see https://github.com/fantasyland/fantasy-land

// 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])
/**
 * 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;
  });
};