2020-01-14 16:55:45 +01:00
|
|
|
# Loops
|
|
|
|
|
|
|
|
RETRO provides several words for creating loops.
|
|
|
|
|
|
|
|
## Unconditional Loops
|
|
|
|
|
|
|
|
An unconditional loop begins with `repeat` and ends with `again`.
|
|
|
|
|
|
|
|
:test repeat #1 n:put sp again ;
|
|
|
|
test
|
|
|
|
|
|
|
|
Unconditional loops must be inside a definition or quote. To exit
|
|
|
|
one of these, use `0;`, `-if;` or `if;`.
|
|
|
|
|
|
|
|
:test #100 repeat 0; dup n:put sp n:dec again ;
|
|
|
|
test
|
|
|
|
|
|
|
|
:test #100 repeat dup #50 eq? [ 'done! s:put nl ] if; n:dec again ;
|
|
|
|
test
|
|
|
|
|
2020-01-14 18:47:33 +01:00
|
|
|
You can also achieve this via recursion:
|
|
|
|
|
|
|
|
:test 0; dup n:put sp n:dec test ;
|
|
|
|
#100 test
|
|
|
|
|
|
|
|
Be careful with recursion as the virtual machine will have a limited
|
|
|
|
amount of space for the address stack and recursing too many times
|
|
|
|
can cause a stack overflow.
|
|
|
|
|
2020-01-14 20:14:55 +01:00
|
|
|
## Conditional Loops
|
|
|
|
|
|
|
|
There are two conditional looping combinators: `while` and `until`.
|
|
|
|
Both take a quote and execute it, checking a returned flag to decide
|
|
|
|
when to stop running.
|
|
|
|
|
|
|
|
#0 [ dup n:put sp n:inc dup #10 eq? ] until
|
|
|
|
#10 [ dup n:put sp n:dec dup n:-zero? ] while
|
|
|
|
|
2020-01-14 16:55:45 +01:00
|
|
|
## Counted Loops
|
|
|
|
|
|
|
|
There are two combinators for counted loops. These are `times` and
|
|
|
|
`times<with-index>`.
|
|
|
|
|
|
|
|
#0 #10 [ dup n:put sp n:inc ] times nl
|
|
|
|
#10 [ I n:put sp ] times<with-index>
|
|
|
|
|
|
|
|
The `times<with-index>` provides an index via the `I`, `J`, and
|
|
|
|
`K` words. `I` will be the index of the current loop, with `J` and
|
|
|
|
`K` being the indexes of the next two older loops.
|
|
|
|
|
|
|
|
The loop indexes can be accessed outside the loop body:
|
|
|
|
|
|
|
|
:display I n:square n:put sp ;
|
|
|
|
:squares [ display ] times<with-index> nl ;
|
|
|
|
#100 squares
|
2020-01-14 18:47:33 +01:00
|
|
|
|
|
|
|
## Tradeoffs
|
|
|
|
|
|
|
|
The unconditional loop form is more efficient as it's just a
|
|
|
|
simple jump operation. The `times` counted loops are a little
|
|
|
|
slower, but can be cleaner and more readable in many cases. The
|
|
|
|
`times<with-index>` form is significantly slower than the other
|
|
|
|
two forms.
|