Big, buggy commit
:for clauses now have finalizers! This means (in-file "path") now works. This meant I had to do some restructuring of many nasty pieces of code, but I believe it works. cl-next was broken up into cl-next/acc and cl-next/for. Accumulators have to pass :acc to (cl-next/acc ...). I plan for :for clauses to do the same. I fixed tests.scm and README.md to reflect the de-racketification of the for loops.
This commit is contained in:
parent
1a826f86e2
commit
0c110dd080
4 changed files with 175 additions and 126 deletions
46
README.md
46
README.md
|
@ -5,10 +5,10 @@ WARNING: CURRENTLY PRE-ALPHA. The examples in this document are not consistent w
|
|||
goof-loops aims to be an amalgamation of the racket for loops and Alex Shinn's (chibi-loop). We are many that found racket's for loops a breeze of fresh air, but in the end their most general forms (for/fold and for/foldr) are kinda odd to work with. If you choose not to use those general for loops, you cannot express arbitrary transformations, like say a fibonacci sequence, since for clauses cannot reference eachother. goof-loop tries to fix this:
|
||||
|
||||
```
|
||||
(loop ((a (in 0 b))
|
||||
(b (in 1 (+ a b)))
|
||||
(loop ((:for a (in 0 b))
|
||||
(:for b (in 1 (+ a b)))
|
||||
(count (up-from 0 (to 1000)))
|
||||
(acc (listing b)))
|
||||
(:acc acc (listing b)))
|
||||
=> acc
|
||||
(display b) (newline))
|
||||
```
|
||||
|
@ -19,23 +19,23 @@ Compared to foof-loop, some things are added. Apart from minor syntactic changes
|
|||
|
||||
```
|
||||
(define lst '((1 2) dud (3 4) (5 6)))
|
||||
(loop ((a (in-list lst))
|
||||
(loop ((:for a (in-list lst))
|
||||
:when (pair? a)
|
||||
(b (in-list a))
|
||||
(acc (summing b)))
|
||||
(:for b (in-list a))
|
||||
(:acc acc (summing b)))
|
||||
=> acc)
|
||||
```
|
||||
|
||||
This will sum all the sublists of lst and produce the result 21. Any :when, :unless, :break, or :subloop clause will break out a subloop if any subsequent for clauses are found.
|
||||
This will sum all the sublists of lst and produce the result 21. Any :when, :unless, :break, :final, or :subloop clause will break out a subloop if any subsequent for clauses are found.
|
||||
|
||||
Accumulators can be in any of the loop's stages:
|
||||
|
||||
```
|
||||
(loop ((a (in-list '(1 2 3)))
|
||||
(aa (summing a))
|
||||
(loop ((:for a (in-list '(1 2 3)))
|
||||
(:acc aa (summing a))
|
||||
:subloop
|
||||
(b (up-from a (to (+ a 2))))
|
||||
(ab (listing b)))
|
||||
(:for b (up-from a (to (+ a 2))))
|
||||
(:acc ab (listing b)))
|
||||
=> (values aa ab))
|
||||
;; => (values 6 (1 2 2 3 3 4))
|
||||
```
|
||||
|
@ -44,34 +44,32 @@ Accumulators can be in any of the loop's stages:
|
|||
|
||||
### syntactical
|
||||
|
||||
No more (for ...). Every clause is now a for-clause. This is because the addition of subloops and accumulators removed the usefulness of having a simple case that acts just as named let.
|
||||
for-clauses are split into :for and :let clauses. This is because the addition of subloops means we have to treat accumulators differently.
|
||||
|
||||
while and until are removed in favour of :break.
|
||||
|
||||
:when and :unless are added to better control when the loop body is executed (and accumulators accumulated)
|
||||
|
||||
with-clauses are removed in favour of (var (in init [step [stop]])) or (var (folding init [step])) in case of accumulators.
|
||||
with-clauses are removed in favour of (:forvar (in init [step [stop]])) or (:acc var (folding init [step])) in case of accumulators.
|
||||
|
||||
### 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).
|
||||
|
||||
sequence clauses cannot finalize, due to the above thing. The reason for distinguishing between sequences and accumulators is to be able to promote accumulators outwards and finalizers inwards. This is not implemented yet, however.
|
||||
|
||||
Due to clause reordering, positional updates are not supported. If you want to update your loop vars, do so using named update (see below).
|
||||
|
||||
### changes
|
||||
|
||||
(with var [init [step [guard]]]) => (var (in init [step [stop-expr]])). guard was a procedure, but now it is an expression.
|
||||
(with var [init [step [guard]]]) => (:for var (in init [step [stop-expr]])). guard was a procedure, but now it is an expression.
|
||||
|
||||
(with var 10 (- var 1) negative?) => (var (in 10 (- var 10) (negative? var)))
|
||||
(with var 10 (- var 1) negative?) => (:for var (in 10 (- var 10) (negative? var)))
|
||||
|
||||
### similarities
|
||||
|
||||
You can of course still have a larger control of your loops:
|
||||
|
||||
```
|
||||
(loop loopy-loop ((a (up-from 1 (to 11))))
|
||||
(loop loopy-loop ((:for a (up-from 1 (to 11))))
|
||||
=> '()
|
||||
(if (odd? a)
|
||||
(cons (* a (- a)) (loopy-loop))
|
||||
|
@ -85,9 +83,9 @@ Named updates also work.
|
|||
```
|
||||
;; Shamelessly stolen from Taylor Campbell's foof-loop documentation
|
||||
(define (partition list predicate)
|
||||
(loop continue ((element (in-list list))
|
||||
(satisfied (folding '()))
|
||||
(unsatisfied (folding '())))
|
||||
(loop continue ((:for element (in-list list))
|
||||
(:acc satisfied (folding '()))
|
||||
(:acc unsatisfied (folding '())))
|
||||
=> (values (reverse satisfied)
|
||||
(reverse unsatisfied))
|
||||
(if (predicate element)
|
||||
|
@ -100,11 +98,9 @@ Named updates also work.
|
|||
|
||||
|
||||
## Todo
|
||||
Should we add finalizers for sequence-clauses? I can't see the need outside of a potential (in-file ...), which can't be properly supported anyway since I won't do any dynamic-wind stuff.
|
||||
Tests and documentation.
|
||||
|
||||
Add racket #:final clauses.
|
||||
|
||||
Add simple versions of loop. loop/list (done), loop/sum, loop/last, loop/first, and so on.
|
||||
Fix the inlining behavious of some of the :for iterators.
|
||||
|
||||
## foof, what a guy
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue