monad-state
Version:
The State Monad
95 lines (85 loc) • 2.09 kB
JavaScript
/**
*
* @module monad-state
*/
;(() => {
'use strict'
const { inputs } = require('guarded')
const { ap, map: omap } = require('fun-object')
const { any, fun, tuple } = require('fun-type')
const curry = require('fun-curry')
/**
*
* of :: a -> Seed -> [a, Seed]
*
* @function module:monad-state.of
*
* @param {*} a - anything
* @param {*} s - state
*
* @return {Array} [a, s]
*/
const of = (a, s) => [a, s]
/**
*
* map :: (a -> b) -> (s -> [a, s]) -> s -> [b, s]
*
* @function module:monad-state.map
*
* @param {Function} a2b - a -> b
* @param {Function} sa - s -> [a, s]
* @param {*} s - state
*
* @return {Array} [b, s]
*/
const map = (a2b, sa, s) => chain(sa, (a, s1) => of(a2b(a), s1), s)
/**
*
* chain :: (s -> [a, s]) -> (a -> s -> [b, s]) -> s -> [b, s]
*
* @function module:monad-state.chain
*
* @param {Function} sa - s -> [a, s]
* @param {Function} a2sb - a -> s -> [b, s]
* @param {*} s0 - state
*
* @return {Array} [b, s]
*/
const chain = (sa, a2sb, s0) => (([a, s1]) => a2sb(a, s1))(sa(s0))
/**
*
* liftM2 :: ((a, b) -> c) -> (s -> [a, s]) -> (s -> [b, s]) -> s -> [c, s]
*
* @function module:monad-state.liftM2
*
* @param {Function} ab2c - (a, b) -> c
* @param {Function} sa - s -> [a, s]
* @param {Function} sb - s -> [b, s]
* @param {*} s0 - state
*
* @return {Array} [c, s]
*/
const liftM2 = (ab2c, sa, sb, s0) =>
chain(sa, (a1, s1) => map(b1 => ab2c(a1, b1), sb, s1), s0)
/**
*
* run :: s -> (s -> [a, s]) -> a
*
* @function module:monad-state.run
*
* @param {*} s - state
* @param {Function} sa - s -> [a, s]
*
* @return {*} a
*/
const run = (s, sa) => sa(s)[0]
const api = { of, map, chain, liftM2, run }
const guards = omap(inputs, {
of: tuple([any, any]),
map: tuple([fun, fun, any]),
chain: tuple([fun, fun, any]),
liftM2: tuple([fun, fun, fun, any]),
run: tuple([any, fun])
})
module.exports = omap(curry, ap(guards, api))
})()