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