Put your function in a loop until the cycle (pun intended) breaks
gleam
1//// Module to conveniently run function in loop
2////
3//// Use-case for this are:
4//// - Maintain a state while sharing resources easily
5//// - Run operation forever
6//// - Limit cycles a loop can go through
7////
8//// ```gleam
9//// cycle.start(with: #([], 0), run: fn(state) {
10//// let #(is, i) = state
11//// case i < 5 {
12//// True -> {
13//// let i = i + 1
14//// cycle.continue(#(list.prepend(is, i), i))
15//// }
16//// _ -> cycle.stop(is)
17//// }
18//// })
19//// ```
20
21/// Message to the cycler if the cycle should continue or stop with a result.
22pub type Next(state, result) {
23 /// Continue the cycle with new state.
24 Continue(state)
25 /// Stop the cycle with a result.
26 Stop(result)
27}
28
29/// Convenient shortcut to `Continue`.
30pub fn continue(state: state) -> Next(state, result) {
31 Continue(state)
32}
33
34/// Convenient shortcut to `Stop`.
35pub fn stop(result: result) -> Next(state, result) {
36 Stop(result)
37}
38
39type LimitState(state) {
40 LimitState(nth_cycle: Int, state: state)
41}
42
43/// Start a cycle with guard on max cycle, returns like normal `start`, otherwise `Error(Nil)` if n-th cycle has reached the max.
44pub fn safely_start(
45 with state: state,
46 max_cycle max: Int,
47 run function: fn(state) -> Next(state, result),
48) -> Result(result, Nil) {
49 // no one except me and god can understand this piece of snippet
50 // but now only god can understand whatever bullshit happens in here
51 start(LimitState(0, state), fn(state) {
52 case state.nth_cycle <= max {
53 True ->
54 case function(state.state) {
55 Continue(inner_state) ->
56 Continue(LimitState(
57 state: inner_state,
58 nth_cycle: state.nth_cycle + 1,
59 ))
60 Stop(result) -> stop(Ok(result))
61 }
62 _ -> stop(Error(Nil))
63 }
64 })
65}
66
67/// Start a cycle, returns a result if function tell the cycler to stop.
68pub fn start(
69 with state: state,
70 run function: fn(state) -> Next(state, result),
71) -> result {
72 loop(state, function)
73}
74
75fn loop(state: state, function: fn(state) -> Next(state, result)) -> result {
76 case function(state) {
77 Continue(new_state) -> loop(new_state, function)
78 Stop(result) -> result
79 }
80}