crocks
Version:
A collection of well known Algebraic Datatypes for your utter enjoyment.
153 lines (114 loc) • 3.62 kB
JavaScript
/** @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