updated the documentation

Added stop-before, stop-after, in-cycle and in-indexed to the
documentation.

Also clarified (and examplified) the erathostenes example.
This commit is contained in:
Linus 2021-05-11 11:14:22 +02:00
parent 6f0c6e636f
commit 66e435aa92
2 changed files with 74 additions and 15 deletions

View file

@ -25,22 +25,40 @@
* A coherent, simple intefrace for accumulating data in loops, with support for accumulating data over sub-loops
* A looping facility that in almost all cases produces as fast code as a hand-written named let
* An extensible looping facility, where new ways of iterating over data can be easily added
The only other lisp looping facility that I know of that provides these things is Common Lisps iterate package. Iterate does however do a lot of things that are cumbersome to do in portable scheme, and would be prohibitively complicated to implement efficiently in a portable way.
The only other lisp looping facility that I know of that provides these things is Common Lisps iterate package. Iterate does however do a lot of things that are cumbersome to do in portable scheme, and would be prohibitively complicated to implement efficiently in a portable way. Unless, of course, one considers CPS-conversion of arbitrary scheme code using syntax-rules simple.
<subsection title="An example or two">
So, how does it look? A slightly contrived example, a naive sieve of Erathostenes:
<example>
(define (erathostenes n)
(define vec (make-vector n #t))
(loop/list ((:for i (up-from 2 (to n)))
(:when (vector-ref vec i)))
(loop ((:for j (up-from (* 2 i) (to n) (by i))))
(vector-set! vec j #f))
i))
(define vec (make-vector n #t))
(loop/list ((:for i (up-from 2 (:to n)))
(:when (vector-ref vec i)))
;; Here we set all multiples of i to #f
(loop ((:for j (up-from (* 3 i) (:to n) (:by (* i 2)))))
(vector-set! vec j #f))
i))
</example>
Calling `(erathostenes 10)` returns a list of all primes below 10.
The example above can also be written using "subloops", but unless you know the expansion it can be somewhat surprising.
<example>
(define (erathostenes n)
(define vec (make-vector n #t))
(loop ((:for i (up-from 2 (:to n)))
(:acc lst (listing i))
(:when (vector-ref vec i))
(:for j (up-from (* 3 i) (:to n) (:by (* i 2))))
=> lst
(vector-set! vec j #f)))
</example>
Any :for clause following a :break, :when, :unless or :final clause is considered to be a subloop. Any :when clause also affects when accumulating clauses collect values. The expression following => is the final expression: this is the expression returned after the loop ends.
</subsection>
</section>
@ -316,6 +334,30 @@
val)
</example>
</syntax>
<syntax name="in-cycle">
<form>(:for binding (in-cycle iterator))</form>
Binds the values produced by `iterator` to `binding`. Once `iterator` stops, it starts over.
</syntax>
<syntax name="in-indexed">
<form>(:for binding (in-indexed iterator))</form>
Binds `binding` to `(n . value)`, where `n` is the nth value produced by `iterator` and `value` is that value. `n` starts from 0
</syntax>
<syntax name="stop-before">
<form>(:for binding (stop-before iterator pred))</form>
Binds `binding` to the values produced by `iterator` until `pred` applied to that value returns true. The iterator is then considered exhausted. Useful in subloops where one might want to end internal iteration without :break-ing.
</syntax>
<syntax name="stop-after">
<form>(:for binding (stop-after iterator pred))</form>
Binds `binding` to the values produced by `iterator` until `pred` 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.
</syntax>
</spec>
</subsection>