UNPKG

crocks

Version:

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

281 lines (222 loc) 7.1 kB
/** @license ISC License (c) copyright 2017 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('Result') var _type = require('../core/types').typeFn(type(), VERSION) var fl = require('../core/flNames') var apOrFunc = require('../core/apOrFunc') var compose = require('../core/compose') var isApplicative = require('../core/isApplicative') var isApply = require('../core/isApply') var isArray = require('../core/isArray') var isFunction = require('../core/isFunction') var isSameType = require('../core/isSameType') var isSemigroup = require('../core/isSemigroup') var constant = function (x) { return function () { return x; }; } var _result = _defineUnion({ Err: [ 'a' ], Ok: [ 'b' ] }) Result.Err = compose(Result, _result.Err) Result.Ok = compose(Result, _result.Ok) var _of = Result.Ok var concatApErr = function (m) { return function (x) { return Result.Err(m.either( function (y) { return isSemigroup(x) && isSameType(y, x) ? x.concat(y) : x; }, function () { return x; } )); }; } var concatAltErr = function (r) { return function (l) { return Result.Err(isSemigroup(r) && isSameType(l, r) ? l.concat(r) : r); }; } function runSequence(x) { if(!(isApply(x) || isArray(x))) { throw new TypeError( 'Result.sequence: Must wrap an Apply' ) } return x.map(_of) } function Result(u) { var obj; if(!arguments.length) { throw new TypeError('Result: Must wrap something, try using Err or Ok constructors') } var x = !_result.includes(u) ? _result.Ok(u) : u var equals = function (m) { return isSameType(Result, 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 ("Err" + (_inspect(l))); }, function (r) { return ("Ok" + (_inspect(r))); } ); } function either(f, g) { if(!isFunction(f) || !isFunction(g)) { throw new TypeError('Result.either: Requires both invalid and valid functions') } return _result.caseOf({ Err: f, Ok: g }, x) } function concat(method) { return function(m) { if(!isSameType(Result, m)) { throw new TypeError(("Result." + method + ": Result of Semigroup required")) } return either( Result.Err, _innerConcat(("Result." + method), m) ) } } function swap(f, g) { if(!isFunction(f) || !isFunction(g)) { throw new TypeError('Result.swap: Requires both left and right functions') } return either( compose(Result.Ok, f), compose(Result.Err, g) ) } function coalesce(f, g) { if(!isFunction(f) || !isFunction(g)) { throw new TypeError('Result.coalesce: Requires both left and right functions') } return Result.Ok(either(f, g)) } function bichain(l, r) { var bichainErr = 'Result.bichain: Both arguments must be Result returning functions' if(!(isFunction(l) && isFunction(r))) { throw new TypeError(bichainErr) } var m = either(l, r) if(!isSameType(Result, m)) { throw new TypeError(bichainErr) } return m } function map(method) { return function(fn) { if(!isFunction(fn)) { throw new TypeError(("Result." + method + ": Function required")) } return either( Result.Err, compose(Result.Ok, fn) ) } } function bimap(method) { return function(f, g) { if(!isFunction(f) || !isFunction(g)) { throw new TypeError(("Result." + method + ": Requires both left and right functions")) } return either( compose(Result.Err, f), compose(Result.Ok, g) ) } } function alt(method) { return function(m) { if(!isSameType(Result, m)) { throw new TypeError(("Result." + method + ": Result required")) } return m.either( function (r) { return either(concatAltErr(r), Result.Ok); }, function (r) { return either(function () { return Result.Ok(r); }, Result.Ok); } ) } } function ap(m) { if(!isSameType(Result, m)) { throw new TypeError('Result.ap: Result required') } return either( concatApErr(m), function(fn) { if(!isFunction(fn)) { throw new TypeError('Result.ap: Wrapped value must be a function') } return m.either(Result.Err, function () { return m.map(fn); }) } ) } function chain(method) { return function(fn) { if(!isFunction(fn)) { throw new TypeError(("Result." + method + ": Result returning function required")) } var m = either(Result.Err, fn) if(!isSameType(Result, m)) { throw new TypeError(("Result." + method + ": Function must return a Result")) } return m } } function sequence(f) { if(!(isApplicative(f) || isFunction(f))) { throw new TypeError( 'Result.sequence: Applicative TypeRep or Apply returning function required' ) } var af = apOrFunc(f) return either( compose(af, Result.Err), runSequence ) } function traverse(f, fn) { if(!(isApplicative(f) || isFunction(f))) { throw new TypeError( 'Result.traverse: Applicative TypeRep of Apply returning function required for first argument' ) } if(!isFunction(fn)) { throw new TypeError( 'Result.traverse: Apply returning functions required for both arguments' ) } var af = apOrFunc(f) var m = either(compose(af, Result.Err), fn) if(!(isApply(m) || isArray(m))) { throw new TypeError('Result.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, equals: equals, type: type, either: either, swap: swap, coalesce: coalesce, bichain: bichain, ap: ap, of: of, sequence: sequence, traverse: traverse, alt: alt('alt'), bimap: bimap('bimap'), concat: concat('concat'), map: map('map'), chain: chain('chain') }, 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 = Result, obj ) } Result.of = _of Result.type = type Result[fl.of] = _of Result['@@type'] = _type Result['@@implements'] = _implements( [ 'alt', 'ap', 'bimap', 'chain', 'concat', 'equals', 'map', 'of', 'traverse' ] ) module.exports = Result