UNPKG

crocks

Version:

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

153 lines (114 loc) 3.62 kB
/** @license ISC License (c) copyright 2016 original and current authors */ /** @author Ian Hofmann-Hicks (evil) */ var VERSION = 2 var _implements = require('../core/implements') var _inspect = require('../core/inspect') var type = require('../core/types').type('State') var _type = require('../core/types').typeFn(type(), VERSION) var fl = require('../core/flNames') var Pair = require('../core/Pair') var Unit = require('../core/Unit') var isFunction = require('../core/isFunction') var isSameType = require('../core/isSameType') var _of = function (x) { return State(function (s) { return Pair(x, s); }); } function get(fn) { if(!arguments.length) { return State(function (s) { return Pair(s, s); }) } if(isFunction(fn)) { return State(function (s) { return Pair(fn(s), s); }) } throw new TypeError('State.get: No arguments or function required') } function modify(fn) { if(!isFunction(fn)) { throw new TypeError('State.modify: Function Required') } return State(function (s) { return Pair(Unit(), fn(s)); }) } function State(fn) { var obj; if(!isFunction(fn)) { throw new TypeError('State: Must wrap a function in the form (s -> Pair a s)') } var of = _of var inspect = function () { return ("State" + (_inspect(fn))); } function runWith(state) { var params = [], len = arguments.length - 1; while ( len-- > 0 ) params[ len ] = arguments[ len + 1 ]; var func = params[0]; if ( func === void 0 ) func = 'runWith'; var m = fn(state) if(!isSameType(Pair, m)) { throw new TypeError(("State." + func + ": Must wrap a function in the form (s -> Pair a s)")) } return m } function execWith(s) { var pair = runWith(s, 'execWith') return pair.snd() } function evalWith(s) { var pair = runWith(s, 'evalWith') return pair.fst() } function map(method) { return function(fn) { if(!isFunction(fn)) { throw new TypeError(("State." + method + ": Function required")) } return State(function (s) { var m = runWith(s, method) return Pair(fn(m.fst()), m.snd()) }) } } function ap(m) { if(!isSameType(State, m)) { throw new TypeError('State.ap: State required') } return State(function (s) { var pair = runWith(s, 'ap') var fn = pair.fst() if(!isFunction(fn)) { throw new TypeError('State.ap: Source value must be a function') } return m.map(fn).runWith(pair.snd()) }) } function chain(method) { return function(fn) { if(!isFunction(fn)) { throw new TypeError(("State." + method + ": State returning function required")) } return State(function (s) { var pair = runWith(s, method) var m = fn(pair.fst()) if(!isSameType(State, m)) { throw new TypeError(("State." + method + ": Function must return another State")) } return m.runWith(pair.snd()) }) } } return ( obj = { inspect: inspect, toString: inspect, runWith: runWith, execWith: execWith, evalWith: evalWith, type: type, ap: ap, of: of, map: map('map'), chain: chain('chain') }, obj[fl.of] = of, obj[fl.map] = map(fl.map), obj[fl.chain] = chain(fl.chain), obj['@@type'] = _type, obj.constructor = State, obj ) } State.of = _of State.get = get State.modify = modify State.put = function (x) { return modify(function () { return x; }); } State.type = type State[fl.of] = _of State['@@type'] = _type State['@@implements'] = _implements( [ 'ap', 'chain', 'map', 'of' ] ) module.exports = State