import { Monad } from './Monad'; export interface StateCallback { (s: S): [A, S] } /** * get the state from the internals of the monad */ export const get = () => new State((s: S) => ([s, s])); /** * put */ export const put = (s: S) => new State(() => ([null, s])); /** * modify the state * @summary (S → S) → State */ export const modify = (f: (s: S) => S) => get().chain((s: S) => put(f(s))); /** * gets applies a function to the state putting using the result * as the result of the computation. * @summary (S → A) → State */ export const gets = (f: (s: S) => A) => get().chain((s: S) => state(f(s))); /** * state create a new State monad */ export const state = (a: A) => new State((s: S) => ([a, s])); /** * State is a monadic class that we use to hold information that changes * during computation. * * This implementation is influenced by: * @link https://en.wikipedia.org/wiki/Monad_(functional_programming)#State_monads * @property {s → (a, s)} a */ export class State implements Monad { f: StateCallback; constructor(f: StateCallback) { this.f = f; } static get = get; static put = put; static modify = modify; static gets = gets; static state = state; /** * of wraps a value in the State monad. * @summary A → State */ of(a: A): State { return new State((s: S) => ([a, s])); } /** * map * @summary State → (A → B) → State */ map(f: (a: A) => B): State { return new State((xs: S) => { let [a, s] = this.run(xs); return [f(a), s]; }) } /** * join replaces the outer State with an inner State */ join(): State { return new State((xs: S): [A, S] => { let [a, s] = this.run(xs); return (>a).run(s); }); } /** * chain */ chain(f: (a: A) => State): State { return (this.map(f) as any as State).join(); } /** * evaluate the State returning the final value */ evaluate(s: S): A { return this.run(s)[0]; } /** * execute the State returning the final state. */ execute(s: S): S { return this.run(s)[1]; } /** * run the State yielding the final value and state. * @summary State → S → {A,S} */ run(s: S): [A, S] { return this.f(s); } }