//// 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 } }