export interface State { readonly runState: (x: s) => [a, s]; } export function pure(a: a): State { const result: State = { runState: s => [a, s] }; return result; } export function bind(lhs: State, rhs: (x: a) => State): State { const result: State = { runState: s => { const [a, s2] = lhs.runState(s); return rhs(a).runState(s2); } }; return result; } export function get(): State { const result: State = { runState: s => [s, s] }; return result; } export function put(s: s): State { const result: State = { runState: () => [undefined, s] }; return result; } export function modify(f: (v: s) => s): State { return bind(get(), x => put(f(x))); } export function evalState(act: State, v: s): a { const t = act.runState(v); return t[0]; } export function execState(act: State, v: s): s { const t = act.runState(v); return t[1]; } // -------------------------------------------------------------------- // Generic Monad functions (specialized for State) // -------------------------------------------------------------------- export function mapM(f: (x: a) => State, elems: a[]): State { if (elems.length === 0) { return pure([]); } else { const x = elems[0]; const xs = elems.slice(1); return bind(f(x), y => bind(mapM(f, xs), ys => pure([y].concat(ys)))); } } export function sequence(actions: State[]): State { if (actions.length === 0) { return pure([]); } else { const x = actions[0]; const xs = actions.slice(1); return bind(x, y => bind(sequence(xs), ys => pure([y].concat(ys)))); } }