Current section
Files
Jump to
Current section
Files
src/leviathan.gleam
/// State monad
pub type State(s, a) {
State(run: fn(s) -> #(a, s))
}
/// Apply a state function `st` to an initial state and return a pair of a value and the final state
pub fn go(st: State(s, a), initial: s) -> #(a, s) {
st.run(initial)
}
/// Apply a state function `st` to an initial state and just return the computation's result
pub fn eval(st: State(s, a), initial: s) -> a {
go(st, initial).0
}
/// Apply a state function `st` to an initial state and return the final state
pub fn exec(st: State(s, a), with initial: s) -> s {
go(st, initial).1
}
/// Monadic return that allows you to use gleam's `use` syntax as a replacement for `do` notation
/// Check `do` for examples
pub fn return(x: a) -> State(s, a) {
State(fn(s) { #(x, s) })
}
/// Monadic bind (>>=) that allows you to use gleam's `use` syntax as a replacement for `do` notation
pub fn do(st: State(s, a), f: fn(a) -> State(s, b)) -> State(s, b) {
State(fn(s1) {
case go(st, s1) {
#(x, s2) -> go(f(x), s2)
}
})
}
/// Sets the resulting value to the current state
pub fn get() -> State(s, s) {
State(fn(s) { #(s, s) })
}
/// Sets the state value to a given state `x`
/// Replaces the return value with Nil
pub fn put(x: s) -> State(s, Nil) {
State(fn(_) { #(Nil, x) })
}
/// Apply the function `f` to the current state
/// Replaces the return value with Nil
pub fn modify(f: fn(s) -> s) -> State(s, Nil) {
use x <- do(get())
put(f(x))
}
/// Apply the function `f` to the resulting value of `s`
pub fn map(st: State(s, a), f: fn(a) -> b) -> State(s, b) {
State(fn(s1) {
case go(st, s1) {
#(x, s2) -> #(f(x), s2)
}
})
}