@safareli/free
Version:
Combination of a free applicative functor and free monad
237 lines (212 loc) • 5.07 kB
JavaScript
'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