Packages

Put your function in a loop until the cycle (pun intended) breaks

Current section

Files

Jump to
cycle src cycle.gleam
Raw

src/cycle.gleam

//// Module to conveniently run function in loop
////
//// Use-case for this are:
//// - Maintain a state while sharing resources easily
//// - Run operation forever
//// - Limit cycles a loop can go through
////
//// ```gleam
//// cycle.start(with: #([], 0), run: fn(state) {
//// let #(is, i) = state
//// case i < 5 {
//// True -> {
//// let i = i + 1
//// cycle.continue(#(list.prepend(is, i), i))
//// }
//// _ -> cycle.stop(is)
//// }
//// })
//// ```
/// Message to the cycler if the cycle should continue or stop with a result.
pub type Next(state, result) {
/// Continue the cycle with new state.
Continue(state)
/// Stop the cycle with a result.
Stop(result)
}
/// Convenient shortcut to `Continue`.
pub fn continue(state: state) -> Next(state, result) {
Continue(state)
}
/// Convenient shortcut to `Stop`.
pub fn stop(result: result) -> Next(state, result) {
Stop(result)
}
type LimitState(state) {
LimitState(nth_cycle: Int, state: state)
}
/// Start a cycle with guard on max cycle, returns like normal `start`, otherwise `Error(Nil)` if n-th cycle has reached the max.
pub fn safely_start(
with state: state,
max_cycle max: Int,
run function: fn(state) -> Next(state, result),
) -> Result(result, Nil) {
// no one except me and god can understand this piece of snippet
// but now only god can understand whatever bullshit happens in here
start(LimitState(0, state), fn(state) {
case state.nth_cycle <= max {
True ->
case function(state.state) {
Continue(inner_state) ->
Continue(LimitState(
state: inner_state,
nth_cycle: state.nth_cycle + 1,
))
Stop(result) -> stop(Ok(result))
}
_ -> stop(Error(Nil))
}
})
}
/// Start a cycle, returns a result if function tell the cycler to stop.
pub fn start(
with state: state,
run function: fn(state) -> Next(state, result),
) -> result {
loop(state, function)
}
fn loop(state: state, function: fn(state) -> Next(state, result)) -> result {
case function(state) {
Continue(new_state) -> loop(new_state, function)
Stop(result) -> result
}
}