crocks
Version:
A collection of well known Algebraic Datatypes for your utter enjoyment.
64 lines (48 loc) • 1.79 kB
JavaScript
/** @license ISC License (c) copyright 2016 original and current authors */
/** @author Ian Hofmann-Hicks (evil) */
var curry = require('./curry')
var isArray = require('./isArray')
var isEmpty = require('./isEmpty')
var isFunction = require('./isFunction')
var isObject = require('./isObject')
var isString = require('./isString')
var constant = function (x) { return function () { return x; }; }
var isDefinition =
function (x) { return isString(x) && x.length; }
function caseOf(defs) {
return function(cases, m) {
var tag = m.tag
var def = defs[tag()]
var args = def.reduce(
function (xs, x) { return xs.concat([ m[x].value() ]); },
[]
)
return cases[tag()].apply(null, args)
}
}
var includes =
function (defs) { return function (m) { return !!m && isFunction(m.tag) && Object.keys(defs).indexOf(m.tag()) !== -1; }; }
function construction(def, tag) {
return function() {
var args = [], len = arguments.length;
while ( len-- ) args[ len ] = arguments[ len ];
return def.reduce(function(obj, key, index) {
obj[key] = { value: constant(args[index]) }
return obj
}, { tag: constant(tag) })
}
}
function defineUnion(defs) {
if(!isObject(defs) || isEmpty(defs)) {
throw new TypeError('defineUnion: Argument must be an Object containing definition lists')
}
return Object.keys(defs).reduce(function(obj, tag) {
var def = defs[tag]
if(!isArray(def) || !def.reduce(function (x, y) { return x && isDefinition(y); }, true)) {
throw new TypeError('defineUnion: Definitions must be a list of non-empty string identifiers')
}
obj[tag] = construction(def, tag)
return obj
}, { caseOf: curry(caseOf(defs)), includes: curry(includes(defs)) })
}
module.exports = defineUnion