unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
From: "Linus Björnstam" <linus.bjornstam@veryfast.biz>
To: guile-devel@gnu.org
Subject: Announcing the first stable release of guile-for-loops
Date: Thu, 23 Jan 2020 13:03:27 +0100	[thread overview]
Message-ID: <d09f179a-3fda-4b2d-b620-05e2f7ad4c7e@www.fastmail.com> (raw)

Hiya everybody!

I have spent some time implementing efficient for loops for guile, and they are baked and ready to go. I have worked the last weeks at implementing generalized support for non-tail-recursive loops and am happy to announce for/foldr. It is a generic right fold, with support for delaying it's arguments as either thunks or promises. 

The syntax is more or less the same as racket's loops, and they are generally compatible. The code generated is for almost all cases as fast as hand-rolled code. They are all expressed as left or right folds, and are as such (apart from for/list, but read about that in the documentation) free of mutation. They are all converted to named lets. 

Some examples:

(for/list ((a (in-range 1 6)))
  (* a a)) ;; => (1 4 9 16 25)

(for*/list ((a (in-string "ab")) (b (in-range 1 3)))
  (list a b)) 
;; => ((#\a 1) (#\a 2) (#\b 1) (#\b 2))

There are many more looping constructs, among others: 
for/sum, for/vector, for/or, for/and, for/first, for/last and a side-effecting simple for.

Here is a 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))

The code and documentation is available here: 
https://hg.sr.ht/~bjoli/guile-for-loops

A web-friendly documentation can be found here: 
https://man.sr.ht/%7Ebjoli/for-loops-docs/for-loops.md

The thing I had been waiting for is right fold. That allows us to write loops like guile's map: non-tail recursive:
(for/foldr ((identity '())) ((a (in-list '(1 2 3))))
  (cons (* a a) identity))

becomes equivalent to:

(let loop ((random-identifier '(1 2 3)))
  (if (null? random-identifier)
      '()
      (let ((a (car random-identifier)))
        (cons (* a a) (loop (cdr random-identifier))))))

Happy hacking
Linus Björnstam



             reply	other threads:[~2020-01-23 12:03 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-01-23 12:03 Linus Björnstam [this message]
     [not found] ` <CAGua6m3=DU=G3jkPqMxX5Bw6r4p394Uh3fV6KeUbrf-_iqxAeQ@mail.gmail.com>
2020-01-24 12:13   ` Fwd: Announcing the first stable release of guile-for-loops Stefan Israelsson Tampe
2020-01-24 18:26     ` Nala Ginrut
2020-01-24 21:23     ` Fwd: " Linus Björnstam

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=d09f179a-3fda-4b2d-b620-05e2f7ad4c7e@www.fastmail.com \
    --to=linus.bjornstam@veryfast.biz \
    --cc=guile-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).