guard if in accumulators is now :if.

All auxiliary syntax is now prefixed by :.
This commit is contained in:
Linus 2021-09-27 21:36:02 +02:00
parent 88f138849e
commit 2775e70fd0
4 changed files with 33 additions and 33 deletions

View file

@ -92,7 +92,7 @@
(loop ((:for a (in-list '(1 2 3 4)))
;; this works because :acc bindings are promoted "outwards".
(:break final)
(:acc final (in-value (initial #f) #t (if (= 3 a))))
(:acc final (in-value (:initial #f) #t (:if (= 3 a))))
(:acc acc (listing (cons a b)))))
</pre><p>This means that any clause above the final binding will be executed an extra time before the loop exits:</p>
<pre class="code-example">
@ -166,26 +166,26 @@
</dd></dt><dt><a id="stop-after"><b>Scheme syntax: </b>stop-after</a><dd><code>(:for binding (stop-after iterator pred))</code><br /><p>Binds <code>binding</code> to the values produced by <code>iterator</code> until <code>pred</code> applied to that value returns true. It then produces that last value. The iterator is then considered exhausted. Useful in subloops where one might want to end internal iteration without :break-ing.</p>
</dd></dt></dl></div><div id=":acc-clauses"><h3>:acc-clauses</h3><p>Accumulating clauses differ from :for-clauses in 2 significant ways. They have a final value available in the <code>final-expr</code>, and they keep their state throughout the loop. In the case of a loop with one subloop, the :for-clauses reset their state every time the subloop is entered. :acc-clauses will always keep their state.</p>
<p>Another small thing is that for some :acc-clauses, the <code>binding</code> may sometimes only be visible to the user in the <code>final-expr</code>, but like :for-clauses they sometimes offer the programmer to name the loop variables.</p>
<p>Many accumulating clauses support an <code>if</code> form. If such a clause is given, accumulation will only happen if the guard clause returns true.</p>
<dl><dt><a id="listing"><b>Scheme syntax: </b>listing</a><dd><code>(:acc binding (listing [(:initial init)] expr [if guard]))</code><br /><p>Accumulates <code>expr</code> into a list. ´binding<code>is only accesible in the final-expression. The list is in the same order as the loop bodies were evaluated. If</code>initial<code>is given that will be used as the tail of the accumulated results. It defaults to</code>()`.</p>
</dd></dt><dt><a id="listing-reverse"><b>Scheme syntax: </b>listing-reverse</a><dd><code>(:acc binding (listing-reverse [(:initial init)] expr [if guard]))</code><br /><p>The same as <code>listing</code> but the resulting list in in reverse order. If the order of the resulting list does not matter, this will be faster than the regular listing as it will not preform any reverse at the end.</p>
</dd></dt><dt><a id="appending"><b>Scheme syntax: </b>appending</a><dd><code>(:acc binding (appending [(:initial init)] expr [if guard]))</code><br /><p><code>expr</code> evaluates to a list that is then appended to the accumulated result.</p>
<p>Many accumulating clauses support an <code>:if</code> form. If such a clause is given, accumulation will only happen if the guard clause returns true.</p>
<dl><dt><a id="listing"><b>Scheme syntax: </b>listing</a><dd><code>(:acc binding (listing [(:initial init)] expr [(:if guard)]))</code><br /><p>Accumulates <code>expr</code> into a list. ´binding<code>is only accesible in the final-expression. The list is in the same order as the loop bodies were evaluated. If</code>initial<code>is given that will be used as the tail of the accumulated results. It defaults to</code>()`.</p>
</dd></dt><dt><a id="listing-reverse"><b>Scheme syntax: </b>listing-reverse</a><dd><code>(:acc binding (listing-reverse [(:initial init)] expr [(:if guard)]))</code><br /><p>The same as <code>listing</code> but the resulting list in in reverse order. If the order of the resulting list does not matter, this will be faster than the regular listing as it will not preform any reverse at the end.</p>
</dd></dt><dt><a id="appending"><b>Scheme syntax: </b>appending</a><dd><code>(:acc binding (appending [(:initial init)] expr [(:if guard)]))</code><br /><p><code>expr</code> evaluates to a list that is then appended to the accumulated result.</p>
<pre class="code-example">
(loop ((:for elt (in-list '((1 2) (3 4))))
(:acc acc (appending (:initial '(0)) elt)))
=&gt; acc)
;; =&gt; (0 1 2 3 4)
</pre></dd></dt><dt><a id="appending-reverse"><b>Scheme syntax: </b>appending-reverse</a><dd><code>(:acc binding (appending-reverse [(:initial init)] expr [if guard]))</code><br /><p><code>expr</code> evaluates to a list that is then consed element by element onto the already accumulated results. The default initial value is <code>'()</code>.</p>
</pre></dd></dt><dt><a id="appending-reverse"><b>Scheme syntax: </b>appending-reverse</a><dd><code>(:acc binding (appending-reverse [(:initial init)] expr [(:if guard)]))</code><br /><p><code>expr</code> evaluates to a list that is then consed element by element onto the already accumulated results. The default initial value is <code>'()</code>.</p>
<pre class="code-example">
(loop ((:for elt (in-list '((1 2) (3 4))))
(:acc acc (appending-reverse (:initial '(0)) elt)))
=&gt; acc)
;; =&gt; (4 3 2 1 0)
</pre></dd></dt><dt><a id="summing"><b>Scheme syntax: </b>summing</a><dd><code>(:acc binding (summing [(:initial init)] expr [(if guard)]))</code><br /><p>Adds the result of <code>expr</code> together using <code>+</code>. The default initial value is 0.</p>
</dd></dt><dt><a id="multiplying"><b>Scheme syntax: </b>multiplying</a><dd><code>(:acc binding (multiplying [(:initial init)] expr [(if guard)]))</code><br /><p>Multiplies the result of <code>expr</code> using <code>*</code>. The default initial value is 1.</p>
</dd></dt><dt><a id="hashing"><b>Scheme syntax: </b>hashing</a><dd><code>(:acc binding (hashing [(:initial init)] key value [(if guard)]))</code><br /><p>Adds the mapping <code>(key =&gt; value)</code> to the hashtable <code>binding</code> using equal?-hashing. The initial hash table is an empty hash-table. <code>binding</code> is bound to the hash table throughout the loop, and its content can be mutated in the loop body.</p>
</dd></dt><dt><a id="hashving"><b>Scheme syntax: </b>hashving</a><dd><code>(:acc binding (hashving [(:initial init)] key value [(if guard)]))</code><br /><p>Adds the mapping <code>(key =&gt; value)</code> to the hashtable <code>binding</code> using eqv?-hashing. The initial hash table is an empty hash-table. <code>binding</code> is bound to the hash table throughout the loop, and its content can be mutated in the loop body.</p>
</dd></dt><dt><a id="hashqing"><b>Scheme syntax: </b>hashqing</a><dd><code>(:acc binding (hashqing [(:initial init)] key value [(if guard)]))</code><br /><p>Adds the mapping <code>(key =&gt; value)</code> to a hashtable using eq?-hashing. The initial hash table is an empty hash-table.<code>binding</code> is bound to the hash table throughout the loop, and its can be mutated in the loop body.</p>
</pre></dd></dt><dt><a id="summing"><b>Scheme syntax: </b>summing</a><dd><code>(:acc binding (summing [(:initial init)] expr [(:if guard)]))</code><br /><p>Adds the result of <code>expr</code> together using <code>+</code>. The default initial value is 0.</p>
</dd></dt><dt><a id="multiplying"><b>Scheme syntax: </b>multiplying</a><dd><code>(:acc binding (multiplying [(:initial init)] expr [(:if guard)]))</code><br /><p>Multiplies the result of <code>expr</code> using <code>*</code>. The default initial value is 1.</p>
</dd></dt><dt><a id="hashing"><b>Scheme syntax: </b>hashing</a><dd><code>(:acc binding (hashing [(:initial init)] key value [(:if guard)]))</code><br /><p>Adds the mapping <code>(key =&gt; value)</code> to the hashtable <code>binding</code> using equal?-hashing. The initial hash table is an empty hash-table. <code>binding</code> is bound to the hash table throughout the loop, and its content can be mutated in the loop body.</p>
</dd></dt><dt><a id="hashving"><b>Scheme syntax: </b>hashving</a><dd><code>(:acc binding (hashving [(:initial init)] key value [(:if guard)]))</code><br /><p>Adds the mapping <code>(key =&gt; value)</code> to the hashtable <code>binding</code> using eqv?-hashing. The initial hash table is an empty hash-table. <code>binding</code> is bound to the hash table throughout the loop, and its content can be mutated in the loop body.</p>
</dd></dt><dt><a id="hashqing"><b>Scheme syntax: </b>hashqing</a><dd><code>(:acc binding (hashqing [(:initial init)] key value [(:if guard)]))</code><br /><p>Adds the mapping <code>(key =&gt; value)</code> to a hashtable using eq?-hashing. The initial hash table is an empty hash-table.<code>binding</code> is bound to the hash table throughout the loop, and its can be mutated in the loop body.</p>
</dd></dt><dt><a id="vectoring"><b>Scheme syntax: </b>vectoring</a><dd><code>(:acc binding [index] (vectoring expr [(:length len) [(:fill fill)]]))</code><br /><p>Accumulates the result of <code>expr</code> into a vector. If <code>len</code> and <code>fill</code> is given the vector will be at most <code>len</code> elements long and any unfilled indexes will contain the element <code>fill</code>. The loop will exit when <code>len</code> elements have been accumulated.</p>
<p>If <code>length</code> is not given, the vector will be expanded as required.</p>
<p>A vectoring clause adds an implicit <code>(:break (= index len))</code> after the vectoring clause. Once the last element of the vector is filled, the loop will stop and no subsequent clauses or body will be executed.</p>

View file

@ -140,7 +140,7 @@
(loop ((:for a (in-list '(1 2 3 4)))
;; this works because :acc bindings are promoted "outwards".
(:break final)
(:acc final (in-value (initial #f) #t (if (= 3 a))))
(:acc final (in-value (:initial #f) #t (:if (= 3 a))))
(:acc acc (listing (cons a b)))))
</example>
@ -388,23 +388,23 @@
Another small thing is that for some :acc-clauses, the `binding` may sometimes only be visible to the user in the `final-expr`, but like :for-clauses they sometimes offer the programmer to name the loop variables.
Many accumulating clauses support an `if` form. If such a clause is given, accumulation will only happen if the guard clause returns true.
Many accumulating clauses support an `:if` form. If such a clause is given, accumulation will only happen if the guard clause returns true.
<spec>
<syntax name="listing">
<form>(:acc binding (listing [(:initial init)] expr [if guard]))</form>
<form>(:acc binding (listing [(:initial init)] expr [(:if guard)]))</form>
Accumulates `expr` into a list. ´binding` is only accesible in the final-expression. The list is in the same order as the loop bodies were evaluated. If `initial` is given that will be used as the tail of the accumulated results. It defaults to `'()`.
</syntax>
<syntax name="listing-reverse">
<form>(:acc binding (listing-reverse [(:initial init)] expr [if guard]))</form>
<form>(:acc binding (listing-reverse [(:initial init)] expr [(:if guard)]))</form>
The same as `listing` but the resulting list in in reverse order. If the order of the resulting list does not matter, this will be faster than the regular listing as it will not preform any reverse at the end.
</syntax>
<syntax name="appending">
<form>(:acc binding (appending [(:initial init)] expr [if guard]))</form>
<form>(:acc binding (appending [(:initial init)] expr [(:if guard)]))</form>
`expr` evaluates to a list that is then appended to the accumulated result.
@ -417,7 +417,7 @@
</syntax>
<syntax name="appending-reverse">
<form>(:acc binding (appending-reverse [(:initial init)] expr [if guard]))</form>
<form>(:acc binding (appending-reverse [(:initial init)] expr [(:if guard)]))</form>
`expr` evaluates to a list that is then consed element by element onto the already accumulated results. The default initial value is `'()`.
@ -430,31 +430,31 @@
</syntax>
<syntax name="summing">
<form>(:acc binding (summing [(:initial init)] expr [(if guard)]))</form>
<form>(:acc binding (summing [(:initial init)] expr [(:if guard)]))</form>
Adds the result of `expr` together using `+`. The default initial value is 0.
</syntax>
<syntax name="multiplying">
<form>(:acc binding (multiplying [(:initial init)] expr [(if guard)]))</form>
<form>(:acc binding (multiplying [(:initial init)] expr [(:if guard)]))</form>
Multiplies the result of `expr` using `*`. The default initial value is 1.
</syntax>
<syntax name="hashing">
<form>(:acc binding (hashing [(:initial init)] key value [(if guard)]))</form>
<form>(:acc binding (hashing [(:initial init)] key value [(:if guard)]))</form>
Adds the mapping `(key => value)` to the hashtable `binding` using equal?-hashing. The initial hash table is an empty hash-table. `binding` is bound to the hash table throughout the loop, and its content can be mutated in the loop body.
</syntax>
<syntax name="hashving">
<form>(:acc binding (hashving [(:initial init)] key value [(if guard)]))</form>
<form>(:acc binding (hashving [(:initial init)] key value [(:if guard)]))</form>
Adds the mapping `(key => value)` to the hashtable `binding` using eqv?-hashing. The initial hash table is an empty hash-table. `binding` is bound to the hash table throughout the loop, and its content can be mutated in the loop body.
</syntax>
<syntax name="hashqing">
<form>(:acc binding (hashqing [(:initial init)] key value [(if guard)]))</form>
<form>(:acc binding (hashqing [(:initial init)] key value [(:if guard)]))</form>
Adds the mapping `(key => value)` to a hashtable using eq?-hashing. The initial hash table is an empty hash-table.`binding` is bound to the hash table throughout the loop, and its can be mutated in the loop body.
</syntax>

View file

@ -33,7 +33,7 @@
;; Auxiliary syntax for the iterators.
:gen
;; auxiliary syntax for some accumulators
:initial
:initial :if
;; auxiliary auxiliary syntax
;; for vectoring
:length :fill

View file

@ -373,12 +373,12 @@
(define-syntax accumulating
(syntax-rules (:initial if :acc)
(syntax-rules (:initial :if :acc)
((accumulating :acc (kons final init) ((var) . x) next . rest)
(accumulating :acc (kons final init) ((var cursor) . x) next . rest))
((accumulating :acc (kons final init) ((var cursor) ((:initial i) . x)) n . rest)
(accumulating :acc (kons final i) ((var cursor) x) n . rest))
((accumulating :acc (kons final init) ((var cursor) (expr (if check))) n . rest)
((accumulating :acc (kons final init) ((var cursor) (expr (:if check))) n . rest)
(n ((tmp-kons kons))
((cursor init (if check (tmp-kons expr cursor) cursor)))
()
@ -443,18 +443,18 @@
(syntax-rules ()
((_ name default-make setter)
(define-syntax name
(syntax-rules (:acc if :initial)
(syntax-rules (:acc :if :initial)
((_ :acc ((var) (key value)) n . rest)
(name :acc ((var) (key value (if #t) (:initial default-make))) n . rest))
(name :acc ((var) (key value (:if #t) (:initial default-make))) n . rest))
;; either init or if
((_ :acc ((var) (key value (if guard))) n . rest)
(name :acc ((var) (key value (if guard) (:initial default-make))) n . rest))
((_ :acc ((var) (key value (:if guard))) n . rest)
(name :acc ((var) (key value (:if guard) (:initial default-make))) n . rest))
((_ :acc ((var) (key value (initial init))) n . rest)
(name :acc ((var) (key value (if #t) (:initial init))) n . rest))
(name :acc ((var) (key value (:if #t) (:initial init))) n . rest))
;; both init and if
((_ :acc ((var) (key value (:initial init) (if guard))) n . rest)
(name ((var) (key value (if guard) (:initial init))) n . rest))
((_ :acc ((var) (key value (if guard) (:initial init))) n . rest)
((_ :acc ((var) (key value (:initial init) (:if guard))) n . rest)
(name ((var) (key value (:if guard) (:initial init))) n . rest))
((_ :acc ((var) (key value (:if guard) (:initial init))) n . rest)
(n
((var init))
((dummy (if #f #f) (if guard (setter var key value) (if #f #f))))