Updated the documentation, added pointer to hosted version

This commit is contained in:
Linus 2021-05-11 13:27:09 +02:00
parent 66e435aa92
commit 5a92ba298d
3 changed files with 88 additions and 138 deletions

View file

@ -40,7 +40,9 @@ Accumulators can be in any of the loop's stages:
## Documentation ## Documentation
Is only available in a weird markdown/xml chimaera or in HTML format. This will change. You can find it in documentation doc.xml (for the weird format) and documentation/doc.html for the slightly more accessible HTML format. It looks ugly though. The current WIP documentation can be found here: https://bjoli.srht.site/doc.html
It is written in a weird markdown/xml chimaera. You can find it in documentation doc.xml (for the weird format) and documentation/doc.html for the slightly more accessible HTML format.
## Differences from foof-loop ## Differences from foof-loop
@ -55,6 +57,22 @@ while and until are removed in favour of :break.
with-clauses are removed in favour of (:for var (in init [step [stop]])) in case of loop clauses, or (:acc var (folding init [step])) in case of accumulators. with-clauses are removed in favour of (:for var (in init [step [stop]])) in case of loop clauses, or (:acc var (folding init [step])) in case of accumulators.
### Higher order loop protocol
goof supports a higher order looping protocol, based on srfi-158 generators:
(loop ((:for food (in-list '(banana cake grape cake bean cake)))
(:for true? (in-cycle (in-list '(#t #f)))))
(display "The ")
(display food)
(display " is a ")
(if true?
(display food)
(display "LIE!"))
(newline))
In the above example true? never ends, but restarts every time the list is exhausted.
### Regressions compared to foof-loop ### Regressions compared to foof-loop
only accumulating clauses are visible in the final-expression. This is due to sequence clauses not being promoted through to outer loops (since they should not keep their state if an inner loop is exited). only accumulating clauses are visible in the final-expression. This is due to sequence clauses not being promoted through to outer loops (since they should not keep their state if an inner loop is exited).
@ -71,7 +89,7 @@ Due to clause reordering, positional updates are not supported. If you want to u
### similarities ### similarities
You can of course still have a larger control of your loops: You can of course still have a larger control of when to loop by naming your loop:
``` ```
(loop loopy-loop ((:for a (up-from 1 (to 11)))) (loop loopy-loop ((:for a (up-from 1 (to 11))))
@ -139,63 +157,9 @@ I also provide simplified forms for many common operations. Omitting :for is all
``` ```
### Loop expansion
A goof loop expands into something looking like this:
```
(let* (<outer-let>)
(letrec ((final-function (lambda (<final-binding>) <final-expr>))
(goof-loop (lambda (<accumulator> ... <loop-var> ...)
(if (or <check> ...)
(begin
<for-clause-finalizer> ...
(final-function (<accumulator-finalizer> <accumulator>) ...))
(let ((<body-binding> ... <body-binding-expr>) ...)
(let ((<user-binding> ... <user-binding-expr>) ...)
(match-let ((<parenthesised-pattern> <match-expr>))
(if (and <when-expr> ...)
(cond
((or <user-break> ...)
<for-clause-finalizer> ...
(final-function (<accumulator-finalizer> <accumulator>) ...))
(else
<loop-body>
(goof-loop <accumulate> ... <loop-var-next> ...))
(goof-loop <accumulator> ... <loop-var-next> ...))))))))
(goof-loop <accumulator-init> ... <loop-var-init> ...)))
```
&lt;outer-let&gt;: are provided by accumulators or for clauses for bindings that are not passed as an argument to the loop, for example a vector. The vector is bound here, and the index into the vector is the thing iterated over.
&lt;final-binding&gt; and &lt;final-expr&gt;: When the iteration ends, this function is called with the results of the :acc clauses. In the case of (:acc lst-acc (listing ...)), the name of the accumulator is never lst-acc in the loop body, but only in the &lt;final-expr&gt;. In case of (listing ...) the accumulated results are reversed before the final function.
&lt;accumulator&gt; and &lt;loop-variable&gt;: &lt;accumulator&gt; holds the current state of an accumulator clause. This is not necessarily the same binding as the user provided as the name, as described above. &lt;loop-var&gt; is the current state of a :for clause.
&lt;check&gt;: Checks for :for-clauses. In the case of (in-list ...) this would check for (not (pair? ...)).
&lt;for-clause-finalizer&gt;: some :for clauses need to be finalized. In the case of (in-file ...) the open file handle is closed at any point where the iteration stops.
&lt;accumulator-finalizer&gt;: &lt;accumulator-finalizer&gt; is any preprocessing done to &lt;accumulator&gt; before passing it on to the final-function. In the case of (listing ...) that would be (reverse ...).
&lt;body-binding&gt; and &lt;body-binding-expr&gt;:&lt;body-binding&gt; are the names the user provided for the body bindings. In the case of (:for a (in-list '(1 2 3))) the body binding would be (a (car name-of-loop-variable)). The body binding may be an (ice-9 match) pattern. More on that below.
&lt;parenthesised-pattern&gt; and &lt;match-expr&gt;: If a &lt;user-binding&gt; is not an identifier, it is presumed to be a match-let pattern. The result is bound to a variable and matched against this match-let.
&lt;when-expr&gt;: the user supplied :when or :unless guard expression.
&lt;user-break&gt;: user-supplied :break guard.
&lt;loop-body&gt;, &lt;accumulate&gt;, and &lt;loop-var-next&gt;: The user supplied body of the loop. If the loop is not named (i.e: in loops where the user controls the iteration) an expression for the next loop iteration is added to the body. &lt;accumulate&gt; is the expression the accumulator clause provided to accumulate a new value. For (:acc acc (listing elem)) that is (cons elem acc). &lt;loop-var-next&gt; is the expression evaluated to get the next iteration's loop variable. In the case of (in-list lst) that is (cdr lst). If a loop name is provided there is no implicit next loop.
&lt;accumulator-init&gt; and &lt;loop-var-init&gt;: &lt;accumulator-init&gt; are ALL accumulator init values, including the ones in subloops. For (listing ...) that is the empty list. &lt;loop-var-init&gt; is the initial loop vars.
In case of subloops, those are placed instead of &lt;loop-body&gt;. They use the same final-function, and instead of quitting when any &lt;check&gt; triggers they go out to the outer loop.
### Speed ### Speed
Speed is good. Despite the rather involved expansion above, due to dead-code elimination, the actual expansion shows some good code: Speed is good. Despite the rather involved expansion you can see in the documentation, due to dead-code elimination, the actual expansion shows some good code:
``` ```
> ,opt (loop ((:for a (in-list '(1 2 3 4))) > ,opt (loop ((:for a (in-list '(1 2 3 4)))
@ -210,17 +174,18 @@ $1 = (let loopy-loop ((cursor-1 '()) (cursor '(1 2 3 4)))
(loopy-loop cursor-1 succ))) (loopy-loop cursor-1 succ)))
(reverse cursor-1))) (reverse cursor-1)))
;; loop/list, being less general, produces faster code that can be more easily unroled and optimized. ;; loop/list, being less general, produces faster code that can be more easily optimized
> ,opt (loop/list ((a (in-list '(1 2 3 4))) > ,opt (loop/list ((a (in-list '(1 2 3 4)))
(:when (even? a))) (:when (even? a)))
a) a)
$2 = (list 2 4) $2 = (list 2 4)
;; Removing the opportunity to completely remove the loop ;; Removing the opportunity to completely optimize the loop away
> ,opt (loop/list ((a (in-list (read))) > ,opt (loop/list ((a (in-list (read)))
(:when (even? a))) (:when (even? a)))
a) a)
;; This is actually the preferred way to do it in guile. Guile re-sizes the stack, so no stack overflows
$5 = (let loopy-loop ((cursor (read))) $5 = (let loopy-loop ((cursor (read)))
(if (pair? cursor) (if (pair? cursor)
(let ((a (car cursor)) (succ (cdr cursor))) (let ((a (car cursor)) (succ (cdr cursor)))

View file

@ -242,54 +242,40 @@
<p>Final bindings. Binds whatever variable name you chose to whatever expression you chose in the final-expression.</p> <p>Final bindings. Binds whatever variable name you chose to whatever expression you chose in the final-expression.</p>
<p>register-loop-clause registers the alisting clause so that it can be verified to exist at expansion time.</p> <p>register-loop-clause registers the alisting clause so that it can be verified to exist at expansion time.</p>
</div></div><div id="Loop expansion"><h2>Loop expansion</h2><p>The main chunk of a loop expands into something like the following: A goof loop expands into something looking like this:</p> </div></div><div id="Loop expansion"><h2>Loop expansion</h2><p>The main chunk of a loop expands into something like the following: A goof loop expands into something looking like this:</p>
<pre> <pre class="code-example">
(let* (&lt;outer-binding&gt; ... (let* (OUTER-BINDING ...
final-function (lambda (&lt;final-binding&gt;) &lt;final-expr&gt;)) final-function (lambda (FINAL-BINDING) FINAL-EXPR))
(let goof-loop ((&lt;accumulator&gt; &lt;accumulator-init&gt;) ... (&lt;loop-var&gt; &lt;loop-var-init&gt;) ...) (let goof-loop ((ACCUMULATOR ACCUMULATOR-INIT) ... (LOOP-VAR LOOP-VAR-INIT) ...)
(if (or &lt;check&gt; ...) (if (or CHECK...)
(begin (begin
&lt;for-clause-finalizer&gt; ... FOR-CLAUSE-FINALIZER ...
(final-function (&lt;accumulator-finalizer&gt; &lt;accumulator&gt;) ...)) (final-function (ACCUMULATOR-FINALIZER ACCUMULATOR) ...))
(let ((&lt;body-binding&gt; ... &lt;body-binding-expr&gt;) ...) (let ((BODY-BINDING ... BODY-BINDING-EXPR) ...)
(let ((&lt;user-binding&gt; ... &lt;user-binding-expr&gt;) ...) (let ((USER-BINDING ...USER-BINDING-EXPR) ...)
(match-let ((&lt;parenthesised-pattern&gt; &lt;match-expr&gt;)) (match-let ((PARENTHESISED-PATTERN MATCH-EXPR))
(if (and &lt;when-expr&gt; ...) (if (and WHEN-EXPR ...)
(cond (cond
((or &lt;user-break&gt; ...) ((or USER-BREAK ...)
&lt;for-clause-finalizer&gt; ... FOR-CLAUSE-FINALIZER ...
(final-function (&lt;accumulator-finalizer&gt; &lt;accumulator&gt;) ...)) (final-function (ACCUMULATOR-FINALIZER ACCUMULATOR) ...))
(else (else
&lt;loop-body&gt; LOOP-BODY
(goof-loop &lt;accumulate&gt; ... &lt;loop-var-next&gt; ...)) (goof-loop ACCUMULATE ... LOOP-VAR-NEXT ...))
(goof-loop &lt;accumulator&gt; ... &lt;loop-var-next&gt; ...))))))))) (goof-loop ACCUMULATOR ... LOOP-VAR-NEXT ...)))))))))
</pre><p>OUTER-BINDING: are provided by accumulators or for clauses for bindings that are not passed as an argument to the loop, for example a vector. The vector is bound here, and the index into the vector is the thing iterated over.</p>
&lt;outer-binding&gt;: are provided by accumulators or for clauses for bindings that are not passed as an argument to the loop, for example a vector. The vector is bound here, and the index into the vector is the thing iterated over. <p>FINAL-BINDING and FINAL-EXPR: When the iteration ends, this function is called with the results of the :acc clauses. In the case of (:acc lst-acc (listing …)), the name of the accumulator is never lst-acc in the loop body, but only in the FINAL-EXPR. In case of (listing …) the accumulated results are reversed before the final function.</p>
<p>ACCUMULATOR and LOOP-VAR: ACCUMULATOR holds the current state of an accumulator clause. This is not necessarily the same binding as the user provided as the name, as described above. LOOP-VAR is the current state of a :for clause.</p>
&lt;final-binding&gt; and &lt;final-expr&gt;: When the iteration ends, this function is called with the results of the :acc clauses. In the case of (:acc lst-acc (listing ...)), the name of the accumulator is never lst-acc in the loop body, but only in the &lt;final-expr&gt;. In case of (listing ...) the accumulated results are reversed before the final function. <p>CHECK: Checks for :for-clauses. In the case of (in-list …) this would check for (not (pair? …)).</p>
<p>FOR-CLAUSE-FINALIZER: some :for clauses need to be finalized. In the case of (in-file …) the open file handle is closed at any point where the iteration stops.</p>
&lt;accumulator&gt; and &lt;loop-variable&gt;: &lt;accumulator&gt; holds the current state of an accumulator clause. This is not necessarily the same binding as the user provided as the name, as described above. &lt;loop-var&gt; is the current state of a :for clause. <p>ACCUMULATOR-FINALIZER: ACCUMULATOR-FINALIZER is any preprocessing done to ACCUMULATOR before passing it on to the final-function. In the case of (listing …) that would be (reverse …).</p>
<p>BODY-BINDING and BODY-BINDING-EXPR: BODY-BINDING are the names the user provided for the body bindings. In the case of (:for a (in-list (1 2 3))) the body binding would be (a (car name-of-loop-variable)). The body binding may be an (ice-9 match) pattern. More on that below.</p>
&lt;check&gt;: Checks for :for-clauses. In the case of (in-list ...) this would check for (not (pair? ...)). <p>PARENTHESISED-PATTERN and MATCH-EXPR: If a USER-BINDING is not an identifier, it is presumed to be a match-let pattern. The result is bound to a variable and matched against this match-let.</p>
<p>WHEN-EXPR: the user supplied :when or :unless guard expression.</p>
&lt;for-clause-finalizer&gt;: some :for clauses need to be finalized. In the case of (in-file ...) the open file handle is closed at any point where the iteration stops. <p>USER-BREAK: user-supplied :break guard.</p>
<p>LOOP-BODY, ACCUMULATE, and LOOP-VAR-NEXT: The user supplied body of the loop. If the loop is not named (i.e: in loops where the user controls the iteration) an expression for the next loop iteration is added to the body. ACCUMULATE is the expression the accumulator clause provided to accumulate a new value. For (:acc acc (listing elem)) that is (cons elem acc). LOOP-VAR-NEXT is the expression evaluated to get the next iterations loop variable. In the case of (in-list lst) that is (cdr lst). If a loop name is provided there is no implicit next loop.</p>
&lt;accumulator-finalizer&gt;: &lt;accumulator-finalizer&gt; is any preprocessing done to &lt;accumulator&gt; before passing it on to the final-function. In the case of (listing ...) that would be (reverse ...). <p>ACCUMULATOR-INIT and LOOP-VAR-INIT: ACCUMULATOR-INIT are ALL accumulator init values, including the ones in subloops. For (listing …) that is the empty list. LOOP-VAR-INIT is the initial loop vars.</p>
<p>In case of subloops, those are placed instead of LOOP-BODY. They use the same final-function, and instead of quitting when any CHECK triggers they go out to the outer loop.</p>
&lt;body-binding&gt; and &lt;body-binding-expr&gt;:&lt;body-binding&gt; are the names the user provided for the body bindings. In the case of (:for a (in-list '(1 2 3))) the body binding would be (a (car name-of-loop-variable)). The body binding may be an (ice-9 match) pattern. More on that below. </div><div id="Porting"><h2>Porting</h2><p>The bulk of goof-loop is written in portable syntax-rules. That code can be found in <code>goof-impl.scm</code> and all files under the <code>goof</code> directory. The major non-portable part is the macro that is bound in every loop to the user-given name of the loop. In the guile implementation this is implemented in syntax-case, and should be portable to any r6rs scheme. The guile implementation does a non-hygienic comparison of the variables in the named update, so to not have to deal with unwanted shadowing:</p>
&lt;parenthesised-pattern&gt; and &lt;match-expr&gt;: If a &lt;user-binding&gt; is not an identifier, it is presumed to be a match-let pattern. The result is bound to a variable and matched against this match-let.
&lt;when-expr&gt;: the user supplied :when or :unless guard expression.
&lt;user-break&gt;: user-supplied :break guard.
&lt;loop-body&gt;, &lt;accumulate&gt;, and &lt;loop-var-next&gt;: The user supplied body of the loop. If the loop is not named (i.e: in loops where the user controls the iteration) an expression for the next loop iteration is added to the body. &lt;accumulate&gt; is the expression the accumulator clause provided to accumulate a new value. For (:acc acc (listing elem)) that is (cons elem acc). &lt;loop-var-next&gt; is the expression evaluated to get the next iteration's loop variable. In the case of (in-list lst) that is (cdr lst). If a loop name is provided there is no implicit next loop.
&lt;accumulator-init&gt; and &lt;loop-var-init&gt;: &lt;accumulator-init&gt; are ALL accumulator init values, including the ones in subloops. For (listing ...) that is the empty list. &lt;loop-var-init&gt; is the initial loop vars.
In case of subloops, those are placed instead of &lt;loop-body&gt;. They use the same final-function, and instead of quitting when any &lt;check&gt; triggers they go out to the outer loop.
</pre></div><div id="Porting"><h2>Porting</h2><p>The bulk of goof-loop is written in portable syntax-rules. That code can be found in <code>goof-impl.scm</code> and all files under the <code>goof</code> directory. The major non-portable part is the macro that is bound in every loop to the user-given name of the loop. In the guile implementation this is implemented in syntax-case, and should be portable to any r6rs scheme. The guile implementation does a non-hygienic comparison of the variables in the named update, so to not have to deal with unwanted shadowing:</p>
<pre class="code-example"> <pre class="code-example">
(loop lp ((:for a (up-from 0 10))) (loop lp ((:for a (up-from 0 10)))
=&gt; '() =&gt; '()

View file

@ -550,54 +550,53 @@
<section title="Loop expansion"> <section title="Loop expansion">
The main chunk of a loop expands into something like the following: The main chunk of a loop expands into something like the following:
A goof loop expands into something looking like this: A goof loop expands into something looking like this:
<verbatim> <example>
(let* (&lt;outer-binding&gt; ... (let* (OUTER-BINDING ...
final-function (lambda (&lt;final-binding&gt;) &lt;final-expr&gt;)) final-function (lambda (FINAL-BINDING) FINAL-EXPR))
(let goof-loop ((&lt;accumulator&gt; &lt;accumulator-init&gt;) ... (&lt;loop-var&gt; &lt;loop-var-init&gt;) ...) (let goof-loop ((ACCUMULATOR ACCUMULATOR-INIT) ... (LOOP-VAR LOOP-VAR-INIT) ...)
(if (or &lt;check&gt; ...) (if (or CHECK...)
(begin (begin
&lt;for-clause-finalizer&gt; ... FOR-CLAUSE-FINALIZER ...
(final-function (&lt;accumulator-finalizer&gt; &lt;accumulator&gt;) ...)) (final-function (ACCUMULATOR-FINALIZER ACCUMULATOR) ...))
(let ((&lt;body-binding&gt; ... &lt;body-binding-expr&gt;) ...) (let ((BODY-BINDING ... BODY-BINDING-EXPR) ...)
(let ((&lt;user-binding&gt; ... &lt;user-binding-expr&gt;) ...) (let ((USER-BINDING ...USER-BINDING-EXPR) ...)
(match-let ((&lt;parenthesised-pattern&gt; &lt;match-expr&gt;)) (match-let ((PARENTHESISED-PATTERN MATCH-EXPR))
(if (and &lt;when-expr&gt; ...) (if (and WHEN-EXPR ...)
(cond (cond
((or &lt;user-break&gt; ...) ((or USER-BREAK ...)
&lt;for-clause-finalizer&gt; ... FOR-CLAUSE-FINALIZER ...
(final-function (&lt;accumulator-finalizer&gt; &lt;accumulator&gt;) ...)) (final-function (ACCUMULATOR-FINALIZER ACCUMULATOR) ...))
(else (else
&lt;loop-body&gt; LOOP-BODY
(goof-loop &lt;accumulate&gt; ... &lt;loop-var-next&gt; ...)) (goof-loop ACCUMULATE ... LOOP-VAR-NEXT ...))
(goof-loop &lt;accumulator&gt; ... &lt;loop-var-next&gt; ...))))))))) (goof-loop ACCUMULATOR ... LOOP-VAR-NEXT ...)))))))))
</example>
OUTER-BINDING: are provided by accumulators or for clauses for bindings that are not passed as an argument to the loop, for example a vector. The vector is bound here, and the index into the vector is the thing iterated over.
&lt;outer-binding&gt;: are provided by accumulators or for clauses for bindings that are not passed as an argument to the loop, for example a vector. The vector is bound here, and the index into the vector is the thing iterated over. FINAL-BINDING and FINAL-EXPR: When the iteration ends, this function is called with the results of the :acc clauses. In the case of (:acc lst-acc (listing ...)), the name of the accumulator is never lst-acc in the loop body, but only in the FINAL-EXPR. In case of (listing ...) the accumulated results are reversed before the final function.
&lt;final-binding&gt; and &lt;final-expr&gt;: When the iteration ends, this function is called with the results of the :acc clauses. In the case of (:acc lst-acc (listing ...)), the name of the accumulator is never lst-acc in the loop body, but only in the &lt;final-expr&gt;. In case of (listing ...) the accumulated results are reversed before the final function. ACCUMULATOR and LOOP-VAR: ACCUMULATOR holds the current state of an accumulator clause. This is not necessarily the same binding as the user provided as the name, as described above. LOOP-VAR is the current state of a :for clause.
&lt;accumulator&gt; and &lt;loop-variable&gt;: &lt;accumulator&gt; holds the current state of an accumulator clause. This is not necessarily the same binding as the user provided as the name, as described above. &lt;loop-var&gt; is the current state of a :for clause. CHECK: Checks for :for-clauses. In the case of (in-list ...) this would check for (not (pair? ...)).
&lt;check&gt;: Checks for :for-clauses. In the case of (in-list ...) this would check for (not (pair? ...)). FOR-CLAUSE-FINALIZER: some :for clauses need to be finalized. In the case of (in-file ...) the open file handle is closed at any point where the iteration stops.
&lt;for-clause-finalizer&gt;: some :for clauses need to be finalized. In the case of (in-file ...) the open file handle is closed at any point where the iteration stops. ACCUMULATOR-FINALIZER: ACCUMULATOR-FINALIZER is any preprocessing done to ACCUMULATOR before passing it on to the final-function. In the case of (listing ...) that would be (reverse ...).
&lt;accumulator-finalizer&gt;: &lt;accumulator-finalizer&gt; is any preprocessing done to &lt;accumulator&gt; before passing it on to the final-function. In the case of (listing ...) that would be (reverse ...). BODY-BINDING and BODY-BINDING-EXPR: BODY-BINDING are the names the user provided for the body bindings. In the case of (:for a (in-list '(1 2 3))) the body binding would be (a (car name-of-loop-variable)). The body binding may be an (ice-9 match) pattern. More on that below.
&lt;body-binding&gt; and &lt;body-binding-expr&gt;:&lt;body-binding&gt; are the names the user provided for the body bindings. In the case of (:for a (in-list '(1 2 3))) the body binding would be (a (car name-of-loop-variable)). The body binding may be an (ice-9 match) pattern. More on that below. PARENTHESISED-PATTERN and MATCH-EXPR: If a USER-BINDING is not an identifier, it is presumed to be a match-let pattern. The result is bound to a variable and matched against this match-let.
&lt;parenthesised-pattern&gt; and &lt;match-expr&gt;: If a &lt;user-binding&gt; is not an identifier, it is presumed to be a match-let pattern. The result is bound to a variable and matched against this match-let. WHEN-EXPR: the user supplied :when or :unless guard expression.
&lt;when-expr&gt;: the user supplied :when or :unless guard expression. USER-BREAK: user-supplied :break guard.
&lt;user-break&gt;: user-supplied :break guard. LOOP-BODY, ACCUMULATE, and LOOP-VAR-NEXT: The user supplied body of the loop. If the loop is not named (i.e: in loops where the user controls the iteration) an expression for the next loop iteration is added to the body. ACCUMULATE is the expression the accumulator clause provided to accumulate a new value. For (:acc acc (listing elem)) that is (cons elem acc). LOOP-VAR-NEXT is the expression evaluated to get the next iteration's loop variable. In the case of (in-list lst) that is (cdr lst). If a loop name is provided there is no implicit next loop.
&lt;loop-body&gt;, &lt;accumulate&gt;, and &lt;loop-var-next&gt;: The user supplied body of the loop. If the loop is not named (i.e: in loops where the user controls the iteration) an expression for the next loop iteration is added to the body. &lt;accumulate&gt; is the expression the accumulator clause provided to accumulate a new value. For (:acc acc (listing elem)) that is (cons elem acc). &lt;loop-var-next&gt; is the expression evaluated to get the next iteration's loop variable. In the case of (in-list lst) that is (cdr lst). If a loop name is provided there is no implicit next loop. ACCUMULATOR-INIT and LOOP-VAR-INIT: ACCUMULATOR-INIT are ALL accumulator init values, including the ones in subloops. For (listing ...) that is the empty list. LOOP-VAR-INIT is the initial loop vars.
&lt;accumulator-init&gt; and &lt;loop-var-init&gt;: &lt;accumulator-init&gt; are ALL accumulator init values, including the ones in subloops. For (listing ...) that is the empty list. &lt;loop-var-init&gt; is the initial loop vars.
In case of subloops, those are placed instead of &lt;loop-body&gt;. They use the same final-function, and instead of quitting when any &lt;check&gt; triggers they go out to the outer loop. In case of subloops, those are placed instead of LOOP-BODY. They use the same final-function, and instead of quitting when any CHECK triggers they go out to the outer loop.
</verbatim>
</section> </section>
<section title="Porting"> <section title="Porting">
The bulk of goof-loop is written in portable syntax-rules. That code can be found in `goof-impl.scm` and all files under the `goof` directory. The major non-portable part is the macro that is bound in every loop to the user-given name of the loop. In the guile implementation this is implemented in syntax-case, and should be portable to any r6rs scheme. The guile implementation does a non-hygienic comparison of the variables in the named update, so to not have to deal with unwanted shadowing: The bulk of goof-loop is written in portable syntax-rules. That code can be found in `goof-impl.scm` and all files under the `goof` directory. The major non-portable part is the macro that is bound in every loop to the user-given name of the loop. In the guile implementation this is implemented in syntax-case, and should be portable to any r6rs scheme. The guile implementation does a non-hygienic comparison of the variables in the named update, so to not have to deal with unwanted shadowing: