crocks
Version:
A collection of well known Algebraic Datatypes for your utter enjoyment.
267 lines (208 loc) • 6.07 kB
JavaScript
/** @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