unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
* Announcing the first stable release of guile-for-loops
@ 2020-01-23 12:03 Linus Björnstam
       [not found] ` <CAGua6m3=DU=G3jkPqMxX5Bw6r4p394Uh3fV6KeUbrf-_iqxAeQ@mail.gmail.com>
  0 siblings, 1 reply; 4+ messages in thread
From: Linus Björnstam @ 2020-01-23 12:03 UTC (permalink / raw)
  To: guile-devel

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



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Fwd: Announcing the first stable release of guile-for-loops
       [not found] ` <CAGua6m3=DU=G3jkPqMxX5Bw6r4p394Uh3fV6KeUbrf-_iqxAeQ@mail.gmail.com>
@ 2020-01-24 12:13   ` Stefan Israelsson Tampe
  2020-01-24 18:26     ` Nala Ginrut
  2020-01-24 21:23     ` Fwd: " Linus Björnstam
  0 siblings, 2 replies; 4+ messages in thread
From: Stefan Israelsson Tampe @ 2020-01-24 12:13 UTC (permalink / raw)
  To: guile-devel

[-- Attachment #1: Type: text/plain, Size: 2527 bytes --]

---------- Forwarded message ---------
From: Stefan Israelsson Tampe <stefan.itampe@gmail.com>
Date: Fri, Jan 24, 2020 at 12:42 PM
Subject: Re: Announcing the first stable release of guile-for-loops
To: Linus Björnstam <linus.bjornstam@veryfast.biz>


Would be cool to have those implemented in guile, that would make my
guile-syntax-parse a bit leaner

Regards
Stefan

On Thu, Jan 23, 2020 at 3:03 PM Linus Björnstam <
linus.bjornstam@veryfast.biz> wrote:

> 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
>
>

[-- Attachment #2: Type: text/html, Size: 3496 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Announcing the first stable release of guile-for-loops
  2020-01-24 12:13   ` Fwd: " Stefan Israelsson Tampe
@ 2020-01-24 18:26     ` Nala Ginrut
  2020-01-24 21:23     ` Fwd: " Linus Björnstam
  1 sibling, 0 replies; 4+ messages in thread
From: Nala Ginrut @ 2020-01-24 18:26 UTC (permalink / raw)
  To: Stefan Israelsson Tampe; +Cc: guile-devel

[-- Attachment #1: Type: text/plain, Size: 2714 bytes --]

+1

On Fri, Jan 24, 2020, 20:13 Stefan Israelsson Tampe <stefan.itampe@gmail.com>
wrote:

>
>
> ---------- Forwarded message ---------
> From: Stefan Israelsson Tampe <stefan.itampe@gmail.com>
> Date: Fri, Jan 24, 2020 at 12:42 PM
> Subject: Re: Announcing the first stable release of guile-for-loops
> To: Linus Björnstam <linus.bjornstam@veryfast.biz>
>
>
> Would be cool to have those implemented in guile, that would make my
> guile-syntax-parse a bit leaner
>
> Regards
> Stefan
>
> On Thu, Jan 23, 2020 at 3:03 PM Linus Björnstam <
> linus.bjornstam@veryfast.biz> wrote:
>
>> 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
>>
>>

[-- Attachment #2: Type: text/html, Size: 3956 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Fwd: Announcing the first stable release of guile-for-loops
  2020-01-24 12:13   ` Fwd: " Stefan Israelsson Tampe
  2020-01-24 18:26     ` Nala Ginrut
@ 2020-01-24 21:23     ` Linus Björnstam
  1 sibling, 0 replies; 4+ messages in thread
From: Linus Björnstam @ 2020-01-24 21:23 UTC (permalink / raw)
  To: Stefan Israelsson Tampe, guile-devel

Yeah, when iterating through many different things at the same time it is extremely helpful. 

I would have loved syntax parse when writing the macros :) I read your for loops code in awe, at least until I saw how you "cheated" with set! :-P

My only chance of getting it into guile proper would be to 1. Make a SRFI and survive the SRFI process with my honour intact and 2. Code cleanup. Most of for/emit is OKish, but for/foldr needs to be beaten with a stick, burnt and rewritten. "bending hygiene" doesn't quite cover what I did to make it work. In the end I sort of kind of worked around it by making an API change, but it still stinks. Defining a new loop using for/foldr involves having to do a syntax->datum->syntax. No fun. I could check how racket does it, but given they can do syntax-local-introduce (which is specific to their "hygiene as sets of scopes") I suspect I am out of luck. 

Väl mött
  Linus Björnstam

On Fri, 24 Jan 2020, at 13:13, Stefan Israelsson Tampe wrote:
> 
> 
> ---------- Forwarded message ---------
> From: *Stefan Israelsson Tampe* <stefan.itampe@gmail.com>
> Date: Fri, Jan 24, 2020 at 12:42 PM
> Subject: Re: Announcing the first stable release of guile-for-loops
> To: Linus Björnstam <linus.bjornstam@veryfast.biz>
> 
> 
> Would be cool to have those implemented in guile, that would make my 
> guile-syntax-parse a bit leaner
> 
> Regards
> Stefan
> 
> On Thu, Jan 23, 2020 at 3:03 PM Linus Björnstam 
> <linus.bjornstam@veryfast.biz> wrote:
> > 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 <https://man.sr.ht/~bjoli/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
> >



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2020-01-24 21:23 UTC | newest]

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

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).