Packages

Stack-safe `while do` and `do while` loops in Gleam

Current section

Files

Jump to
gloop src gloop.erl
Raw

src/gloop.erl

-module(gloop).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([blocking_while/3, while/3, blocking_do_while/3, do_while/3]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" This module called `Gloop` introduces stack-safe, tall-call recursive, non-UI blocking `while` loops in Gleam\n"
" The intent is to remove the additional mental burden recursion causes in Gleam.\n"
"\n"
" For an example of how to use this library see gloop_test.gleam in the test folder.\n"
).
-file("src/gloop.gleam", 17).
?DOC(
" This blocking `while` function is stack-safe and checks the condition based on the\n"
" communicated state.\n"
" If the condition is true then the code is run and a new state is generated for the next iteration.\n"
" If the condition is false then the code returns the final state and stops.\n"
" As long as the condition is true, the while loop will continue without blowing up the stack.\n"
" NOTE that this fuction blocks the UI from updating. It is slightly (a few msecs)\n"
" faster than the non-blocking while function so if pure speed is what you are after\n"
" AND you have a good idea of how many loops the function will execute then this function\n"
" might be what you are after. In most cases ( >95% ) this is NOT the function you should use.\n"
).
-spec blocking_while(HKA, fun((HKA) -> boolean()), fun((HKA) -> HKA)) -> HKA.
blocking_while(State, Pre_run_condition, Code_to_run) ->
case Pre_run_condition(State) of
false ->
State;
true ->
New_state = Code_to_run(State),
blocking_while(New_state, Pre_run_condition, Code_to_run)
end.
-file("src/gloop.gleam", 34).
?DOC(
" This `while` function does the same thing as the blocking while function BUT does not block\n"
" the UI from updating and is stack-safe. This is the function to use in the overwhelming\n"
" majority of cases.\n"
).
-spec while(HKB, fun((HKB) -> boolean()), fun((HKB) -> HKB)) -> HKB.
while(State, Pre_run_condition, Code_to_run) ->
Task = gleam@otp@task:async(
fun() -> blocking_while(State, Pre_run_condition, Code_to_run) end
),
gleam@otp@task:await_forever(Task).
-file("src/gloop.gleam", 49).
?DOC(
" This blocking `do while` function checks the condition based on the communicated state at the end\n"
" of a iteration. It therefore runs the code AT LEAST once.\n"
" As the other blocking while function it is stack-safe and a few milliseconds faster than the\n"
" non-blocking do while function. As before, it should not be used in the majority of cases.\n"
).
-spec blocking_do_while(HKC, fun((HKC) -> HKC), fun((HKC) -> boolean())) -> HKC.
blocking_do_while(State, Code_to_run, Post_run_condition) ->
New_state = Code_to_run(State),
case Post_run_condition(New_state) of
false ->
New_state;
true ->
blocking_do_while(New_state, Code_to_run, Post_run_condition)
end.
-file("src/gloop.gleam", 64).
?DOC(
" This non-blocking `do while` function does the same thing as the blocking do while function,\n"
" is stack-safe and does not block the UI.\n"
" Again this is the function to select in the overwhelming majority of cases.\n"
).
-spec do_while(HKD, fun((HKD) -> HKD), fun((HKD) -> boolean())) -> HKD.
do_while(State, Code_to_run, Post_run_condition) ->
Task = gleam@otp@task:async(
fun() -> blocking_do_while(State, Code_to_run, Post_run_condition) end
),
gleam@otp@task:await_forever(Task).