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