UNPKG

crocks

Version:

A collection of well known Algebraic Datatypes for your utter enjoyment.

271 lines (213 loc) 6.62 kB
/** @license ISC License (c) copyright 2016 original and current authors */ /** @author Ian Hofmann-Hicks (evil) */ var VERSION = 4 var _defineUnion = require('../core/defineUnion') var _equals = require('../core/equals') var _implements = require('../core/implements') var _innerConcat = require('../core/innerConcat') var _inspect = require('../core/inspect') var type = require('../core/types').type('Either') var _type = require('../core/types').typeFn(type(), VERSION) var fl = require('../core/flNames') var apOrFunc = require('../core/apOrFunc') var compose = require('../core/compose') var isArray = require('../core/isArray') var isApplicative = require('../core/isApplicative') var isApply = require('../core/isApply') var isFunction = require('../core/isFunction') var isSameType = require('../core/isSameType') var constant = function (x) { return function () { return x; }; } var _either = _defineUnion({ Left: [ 'a' ], Right: [ 'b' ] }) var Left = _either.Left; var Right = _either.Right; Either.Left = compose(Either, Left) Either.Right = compose(Either, Right) var _of = Either.Right function runSequence(x) { if(!(isApply(x) || isArray(x))) { throw new TypeError('Either.sequence: Must wrap an Apply') } return x.map(_of) } function Either(u) { var obj; if(!arguments.length) { throw new TypeError('Either: Must wrap something, try using Left or Right constructors') } var x = !_either.includes(u) ? Right(u) : u var equals = function (m) { return isSameType(Either, m) && either( function (x) { return m.either(function (y) { return _equals(y, x); }, constant(false)); }, function (x) { return m.either(constant(false), function (y) { return _equals(y, x); }); } ); } var of = _of var inspect = function () { return either( function (l) { return ("Left" + (_inspect(l))); }, function (r) { return ("Right" + (_inspect(r))); } ); } function either(f, g) { if(!isFunction(f) || !isFunction(g)) { throw new TypeError('Either.either: Requires both left and right functions') } return _either.caseOf({ Left: f, Right: g }, x) } function concat(method) { return function(m) { if(!isSameType(Either, m)) { throw new TypeError(("Either." + method + ": Either of Semigroup required")) } return either( Either.Left, _innerConcat(("Either." + method), m) ) } } function swap(f, g) { if(!isFunction(f) || !isFunction(g)) { throw new TypeError('Either.swap: Requires both left and right functions') } return either( compose(Either.Right, f), compose(Either.Left, g) ) } function coalesce(f, g) { if(!isFunction(f) || !isFunction(g)) { throw new TypeError('Either.coalesce: Requires both left and right functions') } return Either.Right(either(f, g)) } function bichain(l, r) { var bichainErr = 'Either.bichain: Both arguments must be Either returning functions' if(!(isFunction(l) && isFunction(r))) { throw new TypeError(bichainErr) } var m = either(l, r) if(!isSameType(Either, m)) { throw new TypeError(bichainErr) } return m } function map(method) { return function(fn) { if(!isFunction(fn)) { throw new TypeError(("Either." + method + ": Function required")) } return either(Either.Left, compose(Either.Right, fn)) } } function bimap(method) { return function(f, g) { if(!isFunction(f) || !isFunction(g)) { throw new TypeError(("Either." + method + ": Requires both left and right functions")) } return either( compose(Either.Left, f), compose(Either.Right, g) ) } } function alt(method) { return function(m) { if(!isSameType(Either, m)) { throw new TypeError(("Either." + method + ": Either required")) } return either( constant(m), Either.Right ) } } function ap(m) { if(!either(constant(true), isFunction)) { throw new TypeError('Either.ap: Wrapped value must be a function') } else if(!either(constant(true), constant(isSameType(Either, m)))) { throw new TypeError('Either.ap: Either required') } return either( Either.Left, function (fn) { return m.map(fn); } ) } function chain(method) { return function(fn) { if(!isFunction(fn)) { throw new TypeError(("Either." + method + ": Function required")) } var m = either(Either.Left, fn) if(!isSameType(Either, m)) { throw new TypeError(("Either." + method + ": Function must return an Either")) } return m } } function sequence(f) { if(!(isApplicative(f) || isFunction(f))) { throw new TypeError( 'Either.sequence: Applicative TypeRep or Apply returning function required' ) } var af = apOrFunc(f) return either( compose(af, Either.Left), runSequence ) } function traverse(f, fn) { if(!(isApplicative(f) || isFunction(f))) { throw new TypeError( 'Either.traverse: Applicative TypeRep or Apply returning function required for first argument' ) } if(!isFunction(fn)) { throw new TypeError( 'Either.traverse: Apply returning function required for second argument' ) } var af = apOrFunc(f) var m = either(compose(af, Either.Left), fn) if(!(isApply(m) || isArray(m))) { throw new TypeError( 'Either.traverse: Both functions must return an Apply of the same type' ) } return either( constant(m), constant(m.map(_of)) ) } return ( obj = { inspect: inspect, toString: inspect, either: either, type: type, swap: swap, coalesce: coalesce, bichain: bichain, equals: equals, ap: ap, of: of, sequence: sequence, traverse: traverse, alt: alt('alt'), bimap: bimap('bimap'), concat: concat('concat'), chain: chain('chain'), map: map('map') }, obj[fl.of] = of, obj[fl.equals] = equals, obj[fl.alt] = alt(fl.alt), obj[fl.bimap] = bimap(fl.bimap), obj[fl.concat] = concat(fl.concat), obj[fl.map] = map(fl.map), obj[fl.chain] = chain(fl.chain), obj['@@type'] = _type, obj.constructor = Either, obj ) } Either.of = _of Either.type = type Either[fl.of] = _of Either['@@type'] = _type Either['@@implements'] = _implements( [ 'alt', 'ap', 'bimap', 'chain', 'concat', 'equals', 'map', 'of', 'traverse' ] ) module.exports = Either