-module(leviathan). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([go/2, eval/2, exec/2, return/1, do/2, get/0, put/1, modify/1, map/2]). -export_type([state/2]). -type state(FWC, FWD) :: {state, fun((FWC) -> {FWD, FWC})}. -spec go(state(FWE, FWF), FWE) -> {FWF, FWE}. go(St, Initial) -> (erlang:element(2, St))(Initial). -spec eval(state(FWI, FWJ), FWI) -> FWJ. eval(St, Initial) -> erlang:element(1, go(St, Initial)). -spec exec(state(FWM, any()), FWM) -> FWM. exec(St, Initial) -> erlang:element(2, go(St, Initial)). -spec return(FWQ) -> state(any(), FWQ). return(X) -> {state, fun(S) -> {X, S} end}. -spec do(state(FWU, FWV), fun((FWV) -> state(FWU, FWY))) -> state(FWU, FWY). do(St, F) -> {state, fun(S1) -> case go(St, S1) of {X, S2} -> go(F(X), S2) end end}. -spec get() -> state(FXD, FXD). get() -> {state, fun(S) -> {S, S} end}. -spec put(FXG) -> state(FXG, nil). put(X) -> {state, fun(_) -> {nil, X} end}. -spec modify(fun((FXJ) -> FXJ)) -> state(FXJ, nil). modify(F) -> do(get(), fun(X) -> put(F(X)) end). -spec map(state(FXM, FXN), fun((FXN) -> FXQ)) -> state(FXM, FXQ). map(St, F) -> {state, fun(S1) -> case go(St, S1) of {X, S2} -> {F(X), S2} end end}.