UNPKG

crocks

Version:

A collection of well known Algebraic Datatypes for your utter enjoyment.

176 lines (143 loc) 5.38 kB
/** @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