crocks
Version:
A collection of well known Algebraic Datatypes for your utter enjoyment.
176 lines (143 loc) • 5.38 kB
JavaScript
/** @license ISC License (c) copyright 2018 original and current authors */
/** @author Karthik Iyengar (karthikiyengar) */
var VERSION = 1
var _implements = require('../core/implements')
var _equals = require('../core/equals')
var _inspect = require('../core/inspect')
var _type = require('../core/types').type('Tuple')
var typeFn = require('../core/types').typeFn
var fl = require('../core/flNames')
var isFunction = require('../core/isFunction')
var isInteger = require('../core/isInteger')
var isSameType = require('../core/isSameType')
var isSemigroup = require('../core/isSemigroup')
var constant = function (x) { return function () { return x; }; }
function _Tuple(n) {
if (!(isInteger(n) && n >= 1)) {
throw new TypeError('Tuple: First argument must be an integer')
}
var tupleLength = constant(n)
var type =
constant(_type(n))
var typeString =
typeFn('Tuple', VERSION, n)
var withProps = function (fn) {
fn.type = type
fn.tupleLength = tupleLength
fn['@@type'] = typeString
fn['@@implements'] = _implements([ 'map', 'concat', 'equals' ])
return fn
}
var withLength = function (n, fn) {
return Object.defineProperty(fn, 'length', {
value: n
})
}
/* eslint-disable no-unused-vars */
switch (n) {
case 1: return withProps(function(a) { return Tuple(n, arguments) })
case 2: return withProps(function(a, b) { return Tuple(n, arguments) })
case 3: return withProps(function(a, b, c) { return Tuple(n, arguments) })
case 4: return withProps(function(a, b, c, d) { return Tuple(n, arguments) })
case 5: return withProps(function(a, b, c, d, e) { return Tuple(n, arguments) })
case 6: return withProps(function(a, b, c, d, e, f) { return Tuple(n, arguments) })
case 7: return withProps(function(a, b, c, d, e, f, g) { return Tuple(n, arguments) })
case 8: return withProps(function(a, b, c, d, e, f, g, h) { return Tuple(n, arguments) })
case 9: return withProps(function(a, b, c, d, e, f, g, h, i) { return Tuple(n, arguments) })
case 10: return withProps(function(a, b, c, d, e, f, g, h, i, j) { return Tuple(n, arguments) })
default: return withLength(n, withProps(function() {
var parts = [], len = arguments.length;
while ( len-- ) parts[ len ] = arguments[ len ];
return Tuple(n, parts) }))
}
/* eslint-enable no-unused-vars */
function Tuple(n, args) {
var obj;
var parts = [].slice.call(args)
if (n !== parts.length) {
throw new TypeError(
(n + "-Tuple: Expected " + n + " values, but got " + (parts.length))
)
}
var inspect = function () { return (n + "-Tuple(" + (parts.map(_inspect).join(',')) + " )"); }
function map(method) {
return function(fn) {
if (!isFunction(fn)) {
throw new TypeError((n + "-Tuple." + method + ": Function required"))
}
return Tuple(n, parts
.slice(0, parts.length - 1)
.concat(fn(parts[parts.length - 1]))
)
}
}
var equals = function (m) { return isSameType({ type: type }, m)
&& _equals(parts, m.toArray()); }
function concat(method) {
return function(t) {
if (!isSameType({ type: type }, t)) {
throw new TypeError((n + "-Tuple." + method + ": Tuple of the same length required"))
}
var a = t.toArray()
return Tuple(n, parts.map(function (v, i, o) {
if (!(isSemigroup(a[i]) && isSemigroup(o[i]))) {
throw new TypeError(
(n + "-Tuple." + method + ": Both Tuples must contain Semigroups of the same type")
)
}
if (!isSameType(a[i], o[i])) {
throw new TypeError(
(n + "-Tuple." + method + ": Both Tuples must contain Semigroups of the same type")
)
}
return o[i].concat(a[i])
}))
}
}
function merge(fn) {
if (!isFunction(fn)) {
throw new TypeError((n + "-Tuple.merge: Function required"))
}
return fn.apply(void 0, parts)
}
function mapAll() {
var args = [], len = arguments.length;
while ( len-- ) args[ len ] = arguments[ len ];
if (args.length !== parts.length) {
throw new TypeError(
(n + "-Tuple.mapAll: Requires " + (parts.length) + " functions")
)
}
return Tuple(
n,
parts.map(function (v, i) {
if (!isFunction(args[i])) {
throw new TypeError(
(n + "-Tuple.mapAll: Functions required for all arguments")
)
}
return args[i](v)
})
)
}
function project(index) {
if (!isInteger(index) || index < 1 || index > n) {
throw new TypeError(
(n + "-Tuple.project: Index should be an integer between 1 and " + n)
)
}
return parts[index - 1]
}
function toArray() {
return parts.slice()
}
return ( obj = {
inspect: inspect, toString: inspect, merge: merge,
project: project, mapAll: mapAll, toArray: toArray,
tupleLength: tupleLength, type: type, equals: equals,
map: map('map'),
concat: concat('concat')
}, obj[fl.map] = map(fl.map), obj[fl.concat] = concat(fl.concat), obj[fl.equals] = equals, obj['@@type'] = typeString, obj.constructor = Tuple, obj )
}
}
module.exports = _Tuple