crocks
Version:
A collection of well known Algebraic Datatypes for your utter enjoyment.
144 lines (112 loc) • 3.19 kB
JavaScript
/** @license ISC License (c) copyright 2017 original and current authors */
/** @author Ian Hofmann-Hicks (evil) */
var isApply = require('./isApply')
var isArray = require('./isArray')
var isEmpty = require('./isEmpty')
var isFunction = require('./isFunction')
var isSameType = require('./isSameType')
var isSemigroup = require('./isSemigroup')
var apOrFunc = require('./apOrFunc')
var identity =
function (x) { return x; }
var concat =
function (x) { return function (m) { return x.concat(m); }; }
function runTraverse(name, fn) {
return function(acc, x) {
var m = fn(x)
if(!((isApply(acc) || isArray(acc)) && isSameType(acc, m))) {
throw new TypeError(("Array." + name + ": Must wrap Applys of the same type"))
}
if(isArray(m)) {
return ap(acc, map(function (v) { return concat([ v ]); }, m))
}
return m
.map(function (v) { return concat([ v ]); })
.ap(acc)
}
}
var allFuncs =
function (xs) { return xs.reduce(function (b, i) { return b && isFunction(i); }, true); }
var map =
function (f, m) { return m.map(function (x) { return f(x); }); }
function ap(x, m) {
if(!(m.length && allFuncs(m))) {
throw new TypeError('Array.ap: Second Array must all be functions')
}
return m.reduce(function (acc, f) { return acc.concat(map(f, x)); }, [])
}
function chain(f, m) {
return m.reduce(function(y, x) {
var n = f(x)
if(!isArray(n)) {
throw new TypeError('Array.chain: Function must return an Array')
}
return y.concat(n)
}, [])
}
function sequence(f, m) {
var fn = apOrFunc(f)
return m.reduceRight(runTraverse('sequence', identity), fn([]))
}
function traverse(f, fn, m) {
var af = apOrFunc(f)
return m.reduceRight(runTraverse('traverse', fn), af([]))
}
function fold(m) {
if(isEmpty(m)) {
throw new TypeError(
'Array.fold: Non-empty Array of Semigroups required'
)
}
var head =
m[0]
if(!isSemigroup(head)) {
throw new TypeError('Array.fold: Must contain Semigroups of the same type')
}
return m.reduce(function(x, y) {
if(!isSameType(x, y)) {
throw new TypeError('Array.fold: Must contain Semigroups of the same type')
}
return x.concat(y)
})
}
function foldMap(fn, m) {
if(isEmpty(m)) {
throw new TypeError(
'Array.foldMap: Non-empty Array required'
)
}
var head =
fn(m[0])
if(!isSemigroup(head)) {
throw new TypeError(
'Array.foldMap: Provided function must return Semigroups of the same type'
)
}
return m.length === 1
? head
: m.slice(1).reduce(function(semi, x) {
var val = fn(x)
if(!(isSameType(semi, val) && isSemigroup(val))) {
throw new TypeError(
'Array.foldMap: Provided function must return Semigroups of the same type'
)
}
return semi.concat(val)
}, head)
}
function set(indx, val, m) {
var arr = m.slice()
arr[indx] = val
return arr
}
function unset(indx, m) {
return m.slice(0, indx)
.concat(m.slice(indx + 1))
}
module.exports = {
ap: ap, chain: chain, fold: fold,
foldMap: foldMap, map: map,
sequence: sequence, set: set,
traverse: traverse, unset: unset
}