Updated readme

Small changes.
This commit is contained in:
Linus 2021-05-26 20:32:09 +02:00
parent 189f1d045d
commit 1de0a624f5

View file

@ -1,8 +1,8 @@
# goof-loop - a scheme looping facility
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.
goof-loops aims to be an amalgamation of the racket for loops and Alex Shinn's fantastic (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.
Compared to foof-loop, some things are added. Apart from minor syntactic changes, subloops are supported. The best way is to show:
Compared to foof-loop, some things are added. Apart from minor syntactic changes, subloops are supported and clauses are executed in order. The best way is to show:
``` scheme
(define lst '((1 2) dud (3 4) (5 6)))
@ -13,7 +13,7 @@ Compared to foof-loop, some things are added. Apart from minor syntactic changes
;; => 21
```
Any :when, :unless, :break, :final, :bind, :do or :subloop clause will break out a subloop if any subsequent for clauses are found.
Any :when, :unless, :break, :final, :bind, :do, or :subloop clause will break out a subloop if any subsequent for clauses are found.
## Beta warning
@ -25,7 +25,6 @@ The current WIP documentation can be found here: https://bjoli.srht.site/doc.htm
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.
## Features
### Lexical order of clauses
@ -41,7 +40,7 @@ It is written in a weird markdown/xml chimaera. You can find it in documentation
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.
This of course also means accumulation is done before the body is executed, which is a bit counterintuitive.
This can lead to some things things that seem counter-intuitive, like:
``` scheme
(loop ((:for a (in-list '(1 2 3)))
@ -51,6 +50,8 @@ This of course also means accumulation is done before the body is executed, whic
;; => #(1 2) 1
```
It also means that any loop body is executed _after_ values are accumulated.
### 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 no :acc clause or explicit final-expression is present is present, the return value is unspecified.
@ -83,7 +84,7 @@ Replace that cons with stream-cons and you have a lazy construct.
### Named updates
``` scheme
;; Shamelessly stolen from Taylor Campbell's foof-loop documentation
;; Shamelessly stolen and adapted from Taylor Campbell's foof-loop documentation
(define (partition list predicate)
(loop continue ((:for element (in-list list))
(:acc satisfied (folding '()))
@ -102,7 +103,7 @@ In the presence of subloops, only the loop variables of the innermost loop are e
### Exposing loop variables
The iterator protocol allows exposing the loop variables
The iterator protocol allows exposing the loop variables.
``` scheme
(loop name ((:for elt pair (in-list '(1 2 3))))
@ -121,14 +122,11 @@ goof supports a higher order looping protocol, based on srfi-158 generators:
``` scheme
(loop ((:for food (in-list '(banana cake grape cake bean cake)))
(loop ((:for word (in-list '(true false sant falskt wahr falsch)))
(:for true? (in-cycle (in-list '(#t #f)))))
(display "The ")
(display food)
(display " is a ")
(if true?
(display food)
(display "LIE!"))
(display word)
(display ": ")
(display true?)
(newline))
```
@ -231,12 +229,11 @@ Speed is good. Despite the rather involved expansion you can see in the document
,expand (loop ((:for a (in-list '(1 2 3 4)))
(:when (even? a))
(:acc acc (listing a))))
$0 = (let* ((final-fun
(lambda (acc) ((@@ (goof) values) acc)))
(tmp-kons (@@ (goof) cons)))
$0 = (let ((tmp-kons (@@ (goof) cons)))
(let loop ((cursor-1 '()) (cursor '(1 2 3 4)))
(if ((@@ (goof) not) ((@@ (goof) pair?) cursor))
(final-fun ((@@ (goof) reverse) cursor-1))
(let ((acc ((@@ (goof) reverse) cursor-1)))
((@@ (goof) values) acc))
(let ((a ((@@ (goof) car) cursor))
(succ ((@@ (goof) cdr) cursor)))
(if (even? a)
@ -245,6 +242,7 @@ $0 = (let* ((final-fun
(loop cursor succ))
(loop cursor-1 succ))))))
;; This is mostly fluff that is removed using DCE, unrolling and inlining:
> ,opt (loop ((:for a (in-list '(1 2 3 4)))
(:when (even? a))
@ -298,7 +296,7 @@ $3 = (let loopy-loop ((cursor (read)))
This used to be a pretty vast collection of examples. goof-loof is now different enough from foof loop that you can't expect to carry your foof-loop skills over to goof-loop. There are however two notable regressions.
### Regressions compared to foof-loop
only accumulating clauses are guaranteed to be 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).
only accumulating clauses are guaranteed to be visible in the final-expression in loops that contain subloops. 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).
Due to clause reordering, positional updates are not supported. If you want to update your loop vars, do so using named update (see below).
@ -313,7 +311,7 @@ Figure out if I can do anything about branching. I would love to remove the body
``` scheme
(loop (accumulators ...)
(clauses ...)
clauses ...
=> final-expr)
(loop ((vectoring a)
@ -335,5 +333,7 @@ But this solution isn't great. The current situation isn't either, though. The b
## foof, what a guy
I have previously expressed some admiration for Alex Shinn and I will do it again. The source of chibi loop is extremely elegant, and all but the hairiest part is written in syntax-rules. Not only has he written my two favourite SRFIs, his input in all the other discussions I have seen is always on-point, pragmatic and generally fantastic. He neither knows of this project, nor embraces it in any way. Y'all should go look at the source of (chibi loop) though.
Don't let my code cast any shadow upon him! I just took his code and made it ugly. (chibi loop) is simple, clear, and - perhaps most important - deliberate.
## Licence
goof started off by copying the iterator protocol of (chibi loop), and things sort of went downhill from there. Despite this, there is still quite a lot of code (especially in iterators.scm) that I didn't write myself. I only made it ugly. Thus goof is licensed under the same BSD-styled license Alex uses for chibi-loop.