Licensed under the mozilla public license v2.
A re-implementation of a large-ish chunk of rackets for-macros. It is mostly compatible with racket's macros, with the largest omission being the body-or-break clause and some of the sequence iterators (like in-cycle, which can be covered by circular lists). There are other differences of course, like for/foldr not being on par feature-wise, and all the nicities you get by having a generic sequence interfce.
The macros are usable and produce optimal code in almost all situations. They have been written with a close eye to how the guile optimizer treats the output.
Documentation and installation instructions are found in docs.org or docs.html or in the wiki: https://man.sr.ht/~bjoli/for-loops-docs/for-loops.md. The markdown file has some oddities in it, but that is due to conversion errors going from org->markdown.
For a stable version download, look under "tags". Anything tagged with a version identifier is considered stable. For a global installation, unpack the .tar.gz and copy the "loops" folder to your site dir. To find the side-dir, execute the following at the command-line:
guile -c "(display (%site-dir))"
If you have a local load path, you can move the loops folder there. Import (loops for-loops) and enjoy!
(use-modules (loops for-loops)) (for/list ((ch (in-string "Hel2lo")) #:unless (char-numeric? ch)) (char-upcase ch)) ;; => (#\H #\E #\L #\L #\O) (for*/list ((a (in-range 1 3)) (b (in-range 1 3))) (list a b)) ;; => ((1 1) (1 2) (2 1) (2 2)) ;; A rather naive sieve of erathostenes (define (erathostenes n) (define vec (make-vector n #t)) (for/list ([i (in-range 2 n)] #:when (vector-ref vec i)) (for ([j (in-range/incr (* 2 i) n i)]) (vector-set! vec j #f)) i)) (erathostenes 10) ;; => (2 3 5 7)
This all produces efficient code. The sieve above becomes:
(define (erathostenes n) (let ((vec (make-vector n #t))) (reverse! (let loop ((acc '()) (container233 2)) (cond ((>= container233 n) acc) ((vector-ref vec container233) (let ((acc (cons (begin (let ((start243 (* 2 container233))) (let loop ((container239 start243)) (if (>= container239 n) (values) (begin (vector-set! vec container239 #f) (loop (+ container239 container233)))))) container233) acc))) (loop acc (+ container233 1)))) (else (loop acc (+ container233 1))))))))
Cleaning the code up reveals code that a human would write:
(define (erathostenes n) (define vec (make-vector n #t)) (let loop ((acc '()) (i 2)) (cond ((>= i n) (reverse! acc)) ((vector-ref vec i) (let loop ((j (* 2 i))) (unless (>= j n) (vector-set! vec j #f) (loop (+ j i)))) (loop (cons i acc) (+ i 1))) (else (loop acc (+ i 1))))))
Both code snippets run just as fast, and the simple optimization of just testing odd numbers can trivially be made to both examples.
I want to make these loops slightly more flexible, and allow for things like arbitrary transformations of values (like, say, loop in common lisp). Something like:
(for/last ((count (in-range 100))(a #:first 0 #:then b) (b #:first 1 #:then (+ a b))) (display "FIBONACCI! ") (display b) (newline))
is not possible currently, and doing something similar would mean writing an ugly for/fold. This is a complex rewrite and will be some time into the future. If at all.