Updated the documentation, added pointer to hosted version
This commit is contained in:
parent
66e435aa92
commit
5a92ba298d
3 changed files with 88 additions and 138 deletions
87
README.md
87
README.md
|
@ -40,7 +40,9 @@ Accumulators can be in any of the loop's stages:
|
|||
|
||||
## 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
|
||||
|
@ -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.
|
||||
|
||||
### 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
|
||||
|
||||
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
|
||||
|
||||
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))))
|
||||
|
@ -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> ...)))
|
||||
```
|
||||
|
||||
<outer-let>: 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.
|
||||
|
||||
<accumulator> and <loop-variable>: <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.
|
||||
|
||||
<check>: 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.
|
||||
|
||||
<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 ...).
|
||||
|
||||
<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.
|
||||
|
||||
<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.
|
||||
|
||||
<when-expr>: the user supplied :when or :unless guard expression.
|
||||
|
||||
<user-break>: 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.
|
||||
|
||||
<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.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
### 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)))
|
||||
|
@ -210,17 +174,18 @@ $1 = (let loopy-loop ((cursor-1 '()) (cursor '(1 2 3 4)))
|
|||
(loopy-loop cursor-1 succ)))
|
||||
(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)))
|
||||
(:when (even? a)))
|
||||
a)
|
||||
$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)))
|
||||
(:when (even? 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)))
|
||||
(if (pair? cursor)
|
||||
(let ((a (car cursor)) (succ (cdr cursor)))
|
||||
|
@ -259,4 +224,4 @@ I have previously expressed some admiration for Alex and I will do it again. The
|
|||
|
||||
## Licence
|
||||
|
||||
The same BSD-styled license Alex uses for chibi-loop.
|
||||
The same BSD-styled license Alex uses for chibi-loop.
|
||||
|
|
|
@ -242,54 +242,40 @@
|
|||
<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>
|
||||
</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>
|
||||
(let* (<outer-binding> ...
|
||||
final-function (lambda (<final-binding>) <final-expr>))
|
||||
(let goof-loop ((<accumulator> <accumulator-init>) ... (<loop-var> <loop-var-init>) ...)
|
||||
(if (or <check> ...)
|
||||
<pre class="code-example">
|
||||
(let* (OUTER-BINDING ...
|
||||
final-function (lambda (FINAL-BINDING) FINAL-EXPR))
|
||||
(let goof-loop ((ACCUMULATOR ACCUMULATOR-INIT) ... (LOOP-VAR LOOP-VAR-INIT) ...)
|
||||
(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> ...)
|
||||
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>) ...))
|
||||
((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> ...)))))))))
|
||||
|
||||
<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.
|
||||
|
||||
<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.
|
||||
|
||||
<accumulator> and <loop-variable>: <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.
|
||||
|
||||
<check>: 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.
|
||||
|
||||
<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 ...).
|
||||
|
||||
<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.
|
||||
|
||||
<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.
|
||||
|
||||
<when-expr>: the user supplied :when or :unless guard expression.
|
||||
|
||||
<user-break>: 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.
|
||||
|
||||
<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.
|
||||
|
||||
|
||||
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.
|
||||
</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>
|
||||
LOOP-BODY
|
||||
(goof-loop ACCUMULATE ... LOOP-VAR-NEXT ...))
|
||||
(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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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 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.</p>
|
||||
<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>
|
||||
</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">
|
||||
(loop lp ((:for a (up-from 0 10)))
|
||||
=> '()
|
||||
|
|
|
@ -550,54 +550,53 @@
|
|||
<section title="Loop expansion">
|
||||
The main chunk of a loop expands into something like the following:
|
||||
A goof loop expands into something looking like this:
|
||||
<verbatim>
|
||||
(let* (<outer-binding> ...
|
||||
final-function (lambda (<final-binding>) <final-expr>))
|
||||
(let goof-loop ((<accumulator> <accumulator-init>) ... (<loop-var> <loop-var-init>) ...)
|
||||
(if (or <check> ...)
|
||||
<example>
|
||||
(let* (OUTER-BINDING ...
|
||||
final-function (lambda (FINAL-BINDING) FINAL-EXPR))
|
||||
(let goof-loop ((ACCUMULATOR ACCUMULATOR-INIT) ... (LOOP-VAR LOOP-VAR-INIT) ...)
|
||||
(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> ...)
|
||||
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>) ...))
|
||||
((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> ...)))))))))
|
||||
|
||||
<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.
|
||||
LOOP-BODY
|
||||
(goof-loop ACCUMULATE ... LOOP-VAR-NEXT ...))
|
||||
(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.
|
||||
|
||||
<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.
|
||||
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.
|
||||
|
||||
<accumulator> and <loop-variable>: <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.
|
||||
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.
|
||||
|
||||
<check>: Checks for :for-clauses. In the case of (in-list ...) this would check for (not (pair? ...)).
|
||||
CHECK: 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.
|
||||
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.
|
||||
|
||||
<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 ...).
|
||||
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 ...).
|
||||
|
||||
<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.
|
||||
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.
|
||||
|
||||
<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.
|
||||
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.
|
||||
|
||||
<when-expr>: the user supplied :when or :unless guard expression.
|
||||
WHEN-EXPR: the user supplied :when or :unless guard expression.
|
||||
|
||||
<user-break>: user-supplied :break guard.
|
||||
USER-BREAK: 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.
|
||||
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.
|
||||
|
||||
<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.
|
||||
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.
|
||||
|
||||
|
||||
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>
|
||||
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.
|
||||
</section>
|
||||
<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:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue