// @flow import { HKT } from './HKT' import type { HKT2 } from './HKT' import type { Monad } from './Monad' import type { Tuple } from './Tuple' import * as tuple from './Tuple' class IsState {} export type StateV = (s: S) => Tuple; export type State = HKT2; export function inj(a: StateV): State { return ((a: any): State) } export function prj(fa: State): StateV { return ((fa: any): StateV) } export function get(): State { return inj(s => tuple.inj([s, s])) } export function put(s: S): State { return inj(() => tuple.inj([undefined, s])) } export function modify(f: (s: S) => S): State { return inj(s => tuple.inj([undefined, f(s)])) } export function gets(f: (s: S) => A): State { return chain(s => of(f(s)), get()) } export function runState(sa: State, s: S): Tuple { return prj(sa)(s) } export function evalState(sa: State, s: S): A { return tuple.fst(runState(sa, s)) } export function execState(sa: State, s: S): S { return tuple.snd(runState(sa, s)) } export function map(f: (a: A) => B, fa: State): State { return inj(s => { const t = runState(fa, s) return tuple.inj([f(tuple.fst(t)), tuple.snd(t)]) }) } export function ap(fab: State B>, fa: State): State { return chain(f => map(f, fa), fab) // <= derived } export function of(a: A): State { return inj(s => tuple.inj([a, s])) } export function chain(f: (a: A) => State, fa: State): State { return inj(s => { const t = runState(fa, s) return runState(f(tuple.fst(t)), tuple.snd(t)) }) } if (false) { // eslint-disable-line ({ map, ap, of, chain }: Monad>) }