crocks
Version:
A collection of well known Algebraic Datatypes for your utter enjoyment.
229 lines (177 loc) • 5.75 kB
JavaScript
/** @license ISC License (c) copyright 2016 original and current authors */
/** @author Ian Hofmann-Hicks (evil) */
var VERSION = 4
var _equals = require('./equals')
var _implements = require('./implements')
var _inspect = require('./inspect')
var type = require('./types').type('Pair')
var _type = require('./types').typeFn(type(), VERSION)
var fl = require('./flNames')
var isApplicative = require('./isApplicative')
var isApply = require('./isApply')
var isArray = require('./isArray')
var isFunction = require('./isFunction')
var isSameType = require('./isSameType')
var isSemigroup = require('./isSemigroup')
function Pair(l, r) {
var obj;
if(arguments.length < 2) {
throw new TypeError('Pair: Must provide a first and second value')
}
var fst =
function () { return l; }
var snd =
function () { return r; }
var inspect =
function () { return ("Pair(" + (_inspect(l)) + "," + (_inspect(r)) + " )"); }
var toArray =
function () { return [ l, r ]; }
function merge(fn) {
if(!isFunction(fn)) {
throw new TypeError('Pair.merge: Binary function required')
}
return fn(fst(), snd())
}
function equals(m) {
return isSameType(Pair, m)
&& _equals(m.fst(), fst())
&& _equals(m.snd(), snd())
}
function concat(method) {
return function(m) {
if(!isSameType(Pair, m)) {
throw new TypeError(("Pair." + method + ": Pair required"))
}
var lf = fst()
var ls = snd()
var rf = m.fst()
var rs = m.snd()
if(!(isSemigroup(lf) && isSemigroup(ls))) {
throw new TypeError(("Pair." + method + ": Both Pairs must contain Semigroups of the same type"))
}
if(!(isSameType(lf, rf) && isSameType(ls, rs))) {
throw new TypeError(("Pair." + method + ": Both Pairs must contain Semigroups of the same type"))
}
return Pair(
lf.concat(rf),
ls.concat(rs)
)
}
}
function swap(f, g) {
if(!isFunction(f) || !isFunction(g)) {
throw new TypeError('Pair.swap: Requires both left and right functions')
}
return Pair(g(r), f(l))
}
function map(method) {
return function(fn) {
if(!isFunction(fn)) {
throw new TypeError(("Pair." + method + ": Function required"))
}
return Pair(l, fn(r))
}
}
function bimap(method) {
return function(f, g) {
if(!isFunction(f) || !isFunction(g)) {
throw new TypeError(("Pair." + method + ": Function required for both arguments"))
}
return Pair(f(l), g(r))
}
}
function ap(m) {
if(!isSameType(Pair, m)) {
throw new TypeError('Pair.ap: Pair required')
}
var fn = snd()
if(!isFunction(fn)) {
throw new TypeError('Pair.ap: Function required for second value')
}
var l = fst()
var r = m.fst()
if(!(isSemigroup(l) && isSameType(l, r))) {
throw new TypeError('Pair.ap: Semigroups of the same type is required for first values')
}
return Pair(l.concat(r), fn(m.snd()))
}
function chain(method) {
return function(fn) {
var l = fst()
if(!isFunction(fn)) {
throw new TypeError(("Pair." + method + ": Function required"))
}
if(!isSemigroup(l)) {
throw new TypeError(("Pair." + method + ": Semigroups of the same type required for first values"))
}
var m = fn(snd())
if(!isSameType(Pair, m)) {
throw new TypeError(("Pair." + method + ": Function must return a Pair"))
}
var r = m.fst()
if(!isSameType(l, r)) {
throw new TypeError(("Pair." + method + ": Semigroups of the same type required for first values"))
}
return Pair(
l.concat(r),
m.snd()
)
}
}
function sequence(f) {
if(!(isApplicative(f) || isFunction(f))) {
throw new TypeError(
'Pair.sequence: Applicative TypeRep or Apply returning function required'
)
}
if(!(isApply(r) || isArray(r))) {
throw new TypeError(
'Pair.sequence: Must wrap an Apply in the second'
)
}
return r.map(function (v) { return Pair(l, v); })
}
function traverse(f, fn) {
if(!(isApplicative(f) || isFunction(f))) {
throw new TypeError(
'Pair.traverse: Applicative TypeRep or Apply returning function required for first argument'
)
}
if(!isFunction(fn)) {
throw new TypeError(
'Pair.traverse: Apply returning function required for second argument'
)
}
var m = fn(r)
if(!(isApply(m) || isArray(m))) {
throw new TypeError(
'Pair.traverse: Both functions must return an Apply of the same type'
)
}
return m.map(function (v) { return Pair(l, v); })
}
function extend(method) {
return function(fn) {
if(!isFunction(fn)) {
throw new TypeError(("Pair." + method + ": Function required"))
}
return Pair(l, fn(Pair(l, r)))
}
}
return ( obj = {
inspect: inspect, toString: inspect, fst: fst,
snd: snd, toArray: toArray, type: type, merge: merge, equals: equals,
swap: swap, ap: ap, sequence: sequence, traverse: traverse,
concat: concat('concat'),
map: map('map'),
bimap: bimap('bimap'),
chain: chain('chain'),
extend: extend('extend')
}, obj[fl.equals] = equals, obj[fl.concat] = concat(fl.concat), obj[fl.map] = map(fl.map), obj[fl.bimap] = bimap(fl.bimap), obj[fl.chain] = chain(fl.chain), obj[fl.extend] = extend(fl.extend), obj['@@type'] = _type, obj.constructor = Pair, obj )
}
Pair.type = type
Pair['@@type'] = _type
Pair['@@implements'] = _implements(
[ 'ap', 'bimap', 'chain', 'concat', 'extend', 'equals', 'map', 'traverse' ]
)
module.exports = Pair