UNPKG

@safareli/free

Version:

Combination of a free applicative functor and free monad

237 lines (212 loc) 5.07 kB
'use strict'; var _require = require('sanctuary-type-classes'), of = _require.of, map = _require.map, ap = _require.ap, chain = _require.chain; var patchAll = require('./fl-patch'); // data Free i a // = Ap { x: (Free i b), y: (Free i (b -> a)) } // | Pure { x: a } // | Lift { x: i, f: (b -> a) } // | Chain { x: (Free i b), f: (b -> (Free i a)) } function Free() { throw new TypeError('No direct use of Free constructor is Allowed'); } function Pure(x) { if (!(this instanceof Pure)) { return new Pure(x); } this.x = x; } Pure.prototype = Object.create(Free.prototype); Pure.prototype.constructor = Pure; Pure.prototype.cata = function (d) { return d.Pure(this.x); }; function Lift(x, f) { if (!(this instanceof Lift)) { return new Lift(x, f); } this.x = x; this.f = f; } Lift.prototype = Object.create(Free.prototype); Lift.prototype.constructor = Lift; Lift.prototype.cata = function (d) { return d.Lift(this.x, this.f); }; function Ap(x, y) { if (!(this instanceof Ap)) { return new Ap(x, y); } this.x = x; this.y = y; } Ap.prototype = Object.create(Free.prototype); Ap.prototype.constructor = Ap; Ap.prototype.cata = function (d) { return d.Ap(this.x, this.y); }; function Chain(x, f) { if (!(this instanceof Chain)) { return new Chain(x, f); } this.x = x; this.f = f; } Chain.prototype = Object.create(Free.prototype); Chain.prototype.constructor = Chain; Chain.prototype.cata = function (d) { return d.Chain(this.x, this.f); }; Free.Pure = Pure; Free.Ap = Ap; Free.Lift = Lift; Free.Chain = Chain; var compose = function compose(f, g) { return function (x) { return f(g(x)); }; }; var id = function id(x) { return x; }; /* istanbul ignore next */ Free.Pure.toString = function () { return 'Free.Pure'; }; /* istanbul ignore next */ Free.Ap.toString = function () { return 'Free.Ap'; }; /* istanbul ignore next */ Free.Lift.toString = function () { return 'Free.Lift'; }; /* istanbul ignore next */ Free.Chain.toString = function () { return 'Free.Chain'; }; /* istanbul ignore next */ Free.prototype.toString = function () { return this.cata({ Pure: function Pure(x) { return 'Free.Pure(' + x + ')'; }, Lift: function Lift(x, f) { return 'Free.Lift(' + x + ',=>)'; }, Ap: function Ap(x, y) { return 'Free.Ap(' + x + ',' + y + ')'; }, Chain: function Chain(x, f) { return 'Free.Chain(' + x + ',=>)'; } }); }; Free.of = Free.Pure; Free.liftF = function (command) { return Free.Lift(command, id); }; Free.prototype.map = function (f) { return this.cata({ Pure: function Pure(x) { return Free.Pure(f(x)); }, Lift: function Lift(x, g) { return Free.Lift(x, compose(f, g)); }, Ap: function Ap(x, y) { return Free.Ap(x, map(function (a) { return map(f, a); }, y)); }, Chain: function Chain(x, g) { return Free.Chain(x, function (a) { return map(f, g(a)); }); } }); }; Free.prototype.ap = function (y) { var _this = this; return this.cata({ Pure: function Pure(x) { return map(function (f) { return f(x); }, y); }, Ap: function Ap() { return Free.Ap(_this, y); }, Lift: function Lift() { return Free.Ap(_this, y); }, Chain: function Chain() { return Free.Ap(_this, y); } }); }; Free.prototype.chain = function (f) { var _this2 = this; return this.cata({ Pure: function Pure(x) { return f(x); }, Ap: function Ap() { return Free.Chain(_this2, f); }, Lift: function Lift() { return Free.Chain(_this2, f); }, Chain: function Chain(x, g) { return Free.Chain(x, function (v) { return chain(f, g(v)); }); } }); }; Free.prototype.hoist = function (f) { return this.foldMap(compose(Free.liftF, f), Free); }; Free.prototype.retract = function (m) { return this.foldMap(id, m); }; Free.prototype.foldMap = function (f, m) { return m.chainRec(function (next, done, v) { return v.cata({ Pure: function Pure(x) { return map(done, of(m, x)); }, Lift: function Lift(x, g) { return map(compose(done, g), f(x)); }, Ap: function Ap(x, y) { return map(done, ap(y.foldMap(f, m), x.foldMap(f, m))); }, Chain: function Chain(x, g) { return map(compose(next, g), x.foldMap(f, m)); } }); }, this); }; Free.prototype.graft = function (f) { return this.foldMap(f, Free); }; var chainRecNext = function chainRecNext(value) { return { done: false, value: value }; }; var chainRecDone = function chainRecDone(value) { return { done: true, value: value }; }; Free.chainRec = function (f, i) { return chain(function (_ref) { var done = _ref.done, value = _ref.value; return done ? Free.of(value) : Free.chainRec(f, value); }, f(chainRecNext, chainRecDone, i)); }; patchAll([Free, Free.prototype]); module.exports = Free; //# sourceMappingURL=free.js.map