-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).