UNPKG

crocks

Version:

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

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