crocks
Version:
A collection of well known Algebraic Datatypes for your utter enjoyment.
142 lines (107 loc) • 3.73 kB
JavaScript
/** @license ISC License (c) copyright 2016 original and current authors */
/** @author Ian Hofmann-Hicks (evil) */
var VERSION = 3
var _equals = require('../core/equals')
var _implements = require('../core/implements')
var _inspect = require('../core/inspect')
var _type = require('../core/types').type('Const')
var typeFn = require('../core/types').typeFn
var fl = require('../core/flNames')
var isFunction = require('../core/isFunction')
var isMonoid = require('../core/isMonoid')
var isSameType = require('../core/isSameType')
var isSemigroup = require('../core/isSemigroup')
var typeOrName =
function (m) { return isFunction(m.type) ? m.type() : m.name; }
var constant = function (x) { return function () { return x; }; }
var empties = {
Array: function () { return []; },
String: function () { return ''; }
}
var getEmpty = function (T) { return T[fl.empty] || T.empty || empties[T.name]; }
var validMonoid = function (T) { return isMonoid(T) || T.name === 'String' || T.name === 'Array'; }
function _Const(T) {
if(!isFunction(T)) {
throw new TypeError('Const: TypeRep required for construction')
}
var type =
constant(_type(typeOrName(T)))
var typeString =
typeFn('Const', VERSION, typeOrName(T))
function empty(method) {
return function() {
if(!validMonoid(T)) {
throw new TypeError(((type()) + "." + method + ": Must be fixed to a Monoid"))
}
return Const(getEmpty(T)())
}
}
function of(method) {
return function() {
if(!validMonoid(T)) {
throw new TypeError(((type()) + "." + method + ": Must be fixed to a Monoid"))
}
return Const(getEmpty(T)())
}
}
function Const(value) {
var obj;
if(!isSameType(T, value)) {
throw new TypeError(((type()) + ": " + (typeOrName(T)) + " required"))
}
var inspect =
constant(("" + (type()) + (_inspect(value))))
var valueOf =
constant(value)
var equals =
function (m) { return isSameType(Const, m)
&& _equals(value, m.valueOf()); }
function concat(method) {
return function(m) {
if(!isSemigroup(value)) {
throw new TypeError(((type()) + "." + method + ": Must be fixed to a Semigroup"))
}
if(!isSameType(Const, m)) {
throw new TypeError(((type()) + "." + method + ": " + (type()) + " required"))
}
return Const(value.concat(m.valueOf()))
}
}
function map(method) {
return function(fn) {
if(!isFunction(fn)) {
throw new TypeError(((type()) + "." + method + ": Function required"))
}
return Const(value)
}
}
function ap(m) {
if(!isSemigroup(value)) {
throw new TypeError(((type()) + ".ap: Must be fixed to a Semigroup"))
}
if(!isSameType(Const, m)) {
throw new TypeError(((type()) + ".ap: " + (type()) + " required"))
}
return Const(value.concat(m.valueOf()))
}
return ( obj = {
inspect: inspect, toString: inspect,
valueOf: valueOf, type: type, ap: ap, equals: equals,
concat: concat('concat'),
empty: empty('empty'),
map: map('map'),
of: of('of')
}, obj[fl.concat] = concat(fl.concat), obj[fl.empty] = empty(fl.empty), obj[fl.equals] = equals, obj[fl.map] = map(fl.map), obj[fl.of] = of(fl.of), obj['@@type'] = typeString, obj.constructor = Const, obj )
}
Const.empty = empty('empty')
Const.of = of('of')
Const.type = type
Const[fl.empty] = empty(fl.empty)
Const[fl.of] = of(fl.of)
Const['@@type'] = typeString
Const['@@implements'] = _implements(
[ 'ap', 'concat', 'empty', 'equals', 'map', 'of' ]
)
return Const
}
module.exports = _Const