diff options
| author | Marshall Lochbaum <mwlochbaum@gmail.com> | 2021-07-21 21:52:30 -0400 |
|---|---|---|
| committer | Marshall Lochbaum <mwlochbaum@gmail.com> | 2021-07-21 21:52:30 -0400 |
| commit | 78af096e176ab416d160a0bfeb9e6ffaaecec49d (patch) | |
| tree | d6d9bffdb5ee46a09ff2a5fb08ef771feaa5a1dd /doc/control.md | |
| parent | 82daaa12bc439ed5ad57e012d57294d43c00e8df (diff) | |
Low-stack iteration technique
Diffstat (limited to 'doc/control.md')
| -rw-r--r-- | doc/control.md | 18 |
1 files changed, 13 insertions, 5 deletions
diff --git a/doc/control.md b/doc/control.md index 6ffd8c8b..d3b47d29 100644 --- a/doc/control.md +++ b/doc/control.md @@ -8,13 +8,13 @@ Control structures here are always functions that act on lists of functions, alt The surfeit of ways to write control structures could be a bit of an issue for reading BQN. My hope is that the community can eventually settle on a smaller set of standard forms to recommend so that you won't have to recognize all the variants given here. On the other hand, the cost of using specialized control structures is lower in a large project without too many contributors. In this case BQN's flexibility allows developers to adapt to the project's particular demands (for example, some programs use switch/case statements heavily but most do not). -The useful control structures introduced here are collected as shortened definitions below. +The useful control structures introduced here are collected as shortened definitions below. `While` uses the slightly more complicated implementation that avoids stack overflow, and `DoWhile` and `For` are written in terms of it in order to share this property. The more direct versions with linear stack use appear in the main text. - If β {πβπ@}Β΄ # Also Repeat + If β {πβπ@}Β΄ # Also Repeat IfElse β {cβΏTβΏF: cβΆFβΏT@} - While β {π¨{πβπΎβπ½π©}π©@}Β΄ # While 1βΏ{... to run forever - DoWhile β {π¨{πβπ½πΎπ©}π©@}Β΄ - For β {IβΏCβΏPβΏA: I@ β {πβPβAβC π©}@} + While β {π©{π½βπΎβπ½_π£_πΎβπ½βπΎπ©}π¨@}Β΄ # While 1βΏ{... to run forever + DoWhile β {π@ β While π¨βΏπ©}Β΄ + For β {IβΏCβΏPβΏA: I@ β Whileβ¨C,PβAβ©} # Switch/case statements have many variations; these are a few Match β {ππ¨}Β΄ @@ -196,6 +196,14 @@ The same modifier technique used in `Forever` works for a while loop as well. Be Because the condition is run repeatedly, it has to be a function, and can't be a plain expression as in an if conditional. +### Low-stack version + +The above version of `While` will fail in a fairly small number of iterations, because it consumes a new stack frame with each iteration. While tail call optimization could solve this, detecting the tail call in a compound function like `πβπΎβπ½` is technically difficult and would introduce overhead into a BQN interpreter. However, there is a method to make the number of required stack frames logarithmic in the number of iterations instead of linear: + + While β {π©{π½βπΎβπ½_π£_πΎβπ½βπΎπ©}π¨@}Β΄ + +The innovation is to use `{π½βπΎβπ½_π£_πΎβπ½βπΎπ©}` instead of the equivalent `{π½_π£_πΎβπ½βπΎπ©}` or `{πβπ½βπΎπ©}` (these are the same, as `π` in a modifier is defined as `π½_π£_πΎ`). Here `π½` performs one iteration and `πΎ` tests whether to continue. The simplest approach is to perform one iteration and recurse with the same two functions. The modified approach replaces `π½` with `π½βπΎβπ½`, that is, it doubles it while making sure the condition is still checked each iteration. The doublings compound so that recursion level `n` performs `π½` up to `2βn` times while using on the order of `n` additional stack frames. Only a hundred or two stack frames are needed to give a practically unlimited number of iterations. + ## For To begin with, are you sure you don't want a for-each loop instead? In BQN that's just a function with Each (`Β¨`), and it covers most common uses of a for loop. |
