Made => implicit if we have accumulators
If there are accumulators, their final values will be returned if no final-expr is given. (loop ((:for a (up-from 1 11)) (:acc lst (listing (* a a)))) => lst) becomes simply: (loop ((:for a (up-from 1 11)) (:acc lst (listing (* a a)))))
This commit is contained in:
parent
7a1137e579
commit
93134a1b21
2 changed files with 36 additions and 29 deletions
49
README.md
49
README.md
|
@ -9,8 +9,7 @@ Compared to foof-loop, some things are added. Apart from minor syntactic changes
|
|||
(loop ((:for a (in-list lst))
|
||||
(:when (pair? a))
|
||||
(:for b (in-list a))
|
||||
(:acc acc (summing b)))
|
||||
=> acc)
|
||||
(:acc acc (summing b))))
|
||||
;; => 21
|
||||
```
|
||||
|
||||
|
@ -37,8 +36,7 @@ It is written in a weird markdown/xml chimaera. You can find it in documentation
|
|||
(:when (test? b))
|
||||
(:bind (c (expensive-operation2 b)))
|
||||
(:when test2? c)
|
||||
(:acc acc (listing c))))
|
||||
=> acc)
|
||||
(:acc acc (listing c)))))
|
||||
```
|
||||
|
||||
There is one caveat to this: some accumulating clauses (currently only vectoring with :length specified) have an implicit :break clause. This is tested AFTER the accumulation takes place. So: if the last position of the vector is set, the loop halts.
|
||||
|
@ -47,10 +45,22 @@ There is one caveat to this: some accumulating clauses (currently only vectoring
|
|||
(loop ((:for a (in-list '(1 2 3)))
|
||||
(:acc vec (vectoring a (:length 2)))
|
||||
;; implicit :break (= vec-index 2)
|
||||
(:acc sum (summing a)))
|
||||
=> (values vec sum))
|
||||
(:acc sum (summing a))))
|
||||
;; => #(1 2) 1
|
||||
```
|
||||
|
||||
### Ability to be explicit about returned values
|
||||
If you have no "final expression", denoted by => expr, one is added that returns all final values of the :acc clauses in the loop. If none is present, the return value is unspecified.
|
||||
|
||||
``` scheme
|
||||
(loop ((:for a (up-from 1 5))
|
||||
(:acc sum (summing a))))
|
||||
;; => 10
|
||||
|
||||
(loop ((:for a (up-from 1 5))
|
||||
(:acc sum (summing a)))
|
||||
=> (- sum))
|
||||
;; => -10
|
||||
```
|
||||
|
||||
### Loop naming to make it "fold right"
|
||||
|
@ -66,6 +76,8 @@ You can of course still have a larger control of when to loop by naming your loo
|
|||
;; => (-1 4 -9 16 -25 36 -49 64 -81 100)
|
||||
```
|
||||
|
||||
Replace that cons with stream-cons and you have a lazy construct.
|
||||
|
||||
### Named updates
|
||||
|
||||
``` scheme
|
||||
|
@ -81,7 +93,7 @@ You can of course still have a larger control of when to loop by naming your loo
|
|||
(continue (=> unsatisfied (cons element unsatisfied))))))
|
||||
|
||||
(partition '(1 2 3 4 5) odd?)
|
||||
;; => (values (1 3 5) (2 4))
|
||||
;; => (1 3 5) (2 4)
|
||||
```
|
||||
|
||||
### Exposing loop variables
|
||||
|
@ -123,15 +135,14 @@ In the above example true? never ends, but restarts every time the list is exhau
|
|||
``` scheme
|
||||
|
||||
(loop ((:for elt (in-list '( 1 2 3)))
|
||||
:final (= elt 2)
|
||||
(:final (= elt 2))
|
||||
(:for ab (in-list '(a b)))
|
||||
(:acc acc (listing (cons elt ab)))
|
||||
=> acc))
|
||||
(:acc acc (listing (cons elt ab))))
|
||||
|
||||
;; => ((1 . a) (1 . b) (2 . a) (2 . b))
|
||||
```
|
||||
|
||||
The racket counterpart would result in ((1 . a) (1 . b) (2 . a)). This comes at :final clauses being less efficient than racket's #:final, but not by much.
|
||||
The racket counterpart would result in ((1 . a) (1 . b) (2 . a)). This comes at :final clauses being marginally less efficient than racket's #:final.
|
||||
|
||||
### :for-clauses can refer to eachother
|
||||
|
||||
|
@ -139,9 +150,8 @@ The iterative fibonacci loop is weird to write using for/fold. goof fixes this:
|
|||
``` scheme
|
||||
(loop ((:for a (in 0 b))
|
||||
(:for b (in 1 (+ a b)))
|
||||
(:for count (up-from 0 (to 100)))
|
||||
(:for count (up-from 0 (:to 100)))
|
||||
(:acc acc (listing b)))
|
||||
=> acc
|
||||
(display b) (newline))
|
||||
```
|
||||
### Accumulators and arbitrary code can be placed in subloops
|
||||
|
@ -152,8 +162,7 @@ The iterative fibonacci loop is weird to write using for/fold. goof fixes this:
|
|||
(:do (display "Entering subloop!") (newline))
|
||||
:subloop
|
||||
(:for b (up-from a (:to (+ a 2))))
|
||||
(:acc ab (listing b)))
|
||||
=> (values aa ab))
|
||||
(:acc ab (listing b))))
|
||||
;; => 6 (1 2 2 3 3 4)
|
||||
```
|
||||
|
||||
|
@ -163,8 +172,7 @@ For clauses which bind "body bindings" (every one except (in ...)) can use patte
|
|||
|
||||
``` scheme
|
||||
(loop ((:for (key . val) (in-list '((a . 1) (b . 2) c . 3)))
|
||||
(:acc sum (summing val)))
|
||||
=> sum)
|
||||
(:acc sum (summing val))))
|
||||
;; => 6
|
||||
|
||||
This also works with :bind clauses.
|
||||
|
@ -183,12 +191,12 @@ I also provide simplified forms for many common operations. Omitting :for is all
|
|||
|
||||
(loop/product ((a (in-list '(2 3 4))))
|
||||
a)
|
||||
;; => 24
|
||||
;; => 24
|
||||
|
||||
(loop/first ((a (in-list '(a b c 3 4 d))) (:when (integer? a)))
|
||||
(display a)
|
||||
a)
|
||||
;; => displays 3 and returns 3.
|
||||
;; => displays 3 and returns 3.
|
||||
|
||||
(loop/last ((a (in-list '(a b c d e f))) (:break (eq? a 'e)))
|
||||
a)
|
||||
|
@ -215,8 +223,7 @@ Speed is good. Despite the rather involved expansion you can see in the document
|
|||
``` scheme
|
||||
> ,opt (loop ((:for a (in-list '(1 2 3 4)))
|
||||
(:when (even? a))
|
||||
(:acc acc (listing a)))
|
||||
=> acc)
|
||||
(:acc acc (listing a))))
|
||||
$1 = (let loopy-loop ((cursor-1 '()) (cursor '(1 2 3 4)))
|
||||
(if (pair? cursor)
|
||||
(let ((a (car cursor)) (succ (cdr cursor)))
|
||||
|
|
|
@ -56,14 +56,10 @@
|
|||
|
||||
|
||||
(define-syntax %loop
|
||||
(syntax-rules (=>)
|
||||
((%loop o () => expr body ...)
|
||||
(%loop o ((:for ensure-once (up-from 0 1))) => expr body ...))
|
||||
(syntax-rules ()
|
||||
((%loop o () body ...)
|
||||
(%loop o ((:for ensure-once (up-from 0 1))) body ...))
|
||||
((%loop o name () => expr body ...)
|
||||
(%loop o name ((:for ensure-once (up-from 0 1))) => expr body ...))
|
||||
((%loop o name () body ...)
|
||||
((%loop o name () body ...)
|
||||
(%loop o name ((:for ensure-once (up-from 0 1))) body ...))
|
||||
((%loop o (clauses ...) body ...)
|
||||
(ensure-for-clause #f () (clauses ...) o
|
||||
|
@ -125,8 +121,12 @@
|
|||
(syntax-rules (=> :for :acc :when :unless :break :final :do :bind :subloop)
|
||||
((_ orig name l a v c r f ff user () => expr . body)
|
||||
(emit orig name l a v c r f ff user expr . body))
|
||||
((_ orig name l a v c r f ff user () . body)
|
||||
(emit orig name l a v c r f ff user (if #f #f) . body))
|
||||
((_ orig name l a v c r () ff user () . body)
|
||||
(emit orig name l a v c r () ff user (if #f #f) . body))
|
||||
|
||||
;; If we have no final-expr, but we have final bindings, we return those.
|
||||
((_ orig name l a v c r ((final-binding expr) ...) ff user () . body)
|
||||
(emit orig name l a v c r ((final-binding expr) ...) ff user (values final-binding ...) . body))
|
||||
|
||||
;; user bindings
|
||||
((_ orig name l a v c r f ff ((cur-ul ...) . ul-rest) ((:bind (id id* ... expr) ...) clauses ...) . body)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue