unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* for with break and continue
@ 2022-09-04  9:54 Damien Mattei
  2022-09-04 10:43 ` Jean Abou Samra
  0 siblings, 1 reply; 7+ messages in thread
From: Damien Mattei @ 2022-09-04  9:54 UTC (permalink / raw)
  To: guile-user

i try to make a for with break and continue the way C language do it, i
works with break but if i add a continue feature i then loose the break
feature, here is my code:
(define-syntax for/bc

  (lambda (stx)
    (syntax-case stx ()
      ((kwd (init test incrmt) body ...)

       (with-syntax
((BREAK (datum->syntax #'kwd 'break)))

#'(call/cc
  (lambda (escape)
    (let-syntax
((BREAK (identifier-syntax (escape))))
      init
      (let loop ()
(when test

      (with-syntax
((CONTINUE (datum->syntax #'kwd 'continue)))

#'(call/cc
 (lambda (next)
   (let-syntax
((CONTINUE (identifier-syntax (next))))
     body ...)))

      incrmt
      (loop))))))))))))

Damien


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

* Re: for with break and continue
  2022-09-04  9:54 for with break and continue Damien Mattei
@ 2022-09-04 10:43 ` Jean Abou Samra
  2022-09-04 12:00   ` Damien Mattei
  0 siblings, 1 reply; 7+ messages in thread
From: Jean Abou Samra @ 2022-09-04 10:43 UTC (permalink / raw)
  To: Damien Mattei, guile-user

Le 04/09/2022 à 11:54, Damien Mattei a écrit :
> i try to make a for with break and continue the way C language do it, i
> works with break but if i add a continue feature i then loose the break
> feature, here is my code:
> (define-syntax for/bc
>
>    (lambda (stx)
>      (syntax-case stx ()
>        ((kwd (init test incrmt) body ...)
>
>         (with-syntax
> ((BREAK (datum->syntax #'kwd 'break)))
>
> #'(call/cc
>    (lambda (escape)
>      (let-syntax
> ((BREAK (identifier-syntax (escape))))
>        init
>        (let loop ()
> (when test
>
>        (with-syntax
> ((CONTINUE (datum->syntax #'kwd 'continue)))
>
> #'(call/cc
>   (lambda (next)
>     (let-syntax
> ((CONTINUE (identifier-syntax (next))))
>       body ...)))
>
>        incrmt
>        (loop))))))))))))



The problem is with the meta level vs. the expanded output level. You have
two nested levels of #' . This (with-syntax ((CONTINUE ...)) ...) is part of
the expanded output, it doesn't run when your macro is expanded. The body of
the (expanded) loop just returns a syntax object. That's not what you want.
Here's a definition that works:

(define-syntax for/bc
   (lambda (stx)
     (syntax-case stx ()
       ((kwd (init test incrmt) body ...)
        (with-syntax ((BREAK (datum->syntax #'kwd 'break))
                      (CONTINUE (datum->syntax #'kwd 'continue)))
          #'(call/cc
             (lambda (escape)
               (let-syntax ((BREAK (identifier-syntax (escape))))
                 init
                 (let loop ()
                   (when test
                     (call/cc
                      (lambda (next)
                        (let-syntax ((CONTINUE (identifier-syntax (next))))
                          body ...)))
                       incrmt
                       (loop)))))))))))

(let ((i #f))
   (for/bc ((set! i 0) (< i 10) (set! i (1+ i)))
     (when (< i 5)
       continue)
     (when (> i 9)
       break)
     (display i)
     (newline)))



You could also use quasisyntax (#` and #,) to get the same effect:


(define-syntax for/bc
   (lambda (stx)
     (syntax-case stx ()
       ((kwd (init test incrmt) body ...)
        #`(call/cc
           (lambda (escape)
             (let-syntax ((#,(datum->syntax #'kwd 'break)
                           (identifier-syntax (escape))))
               init
               (let loop ()
                 (when test
                   (call/cc
                    (lambda (next)
                      (let-syntax ((#,(datum->syntax #'kwd 'continue)
                                    (identifier-syntax (next))))
                        body ...)))
                   incrmt
                   (loop))))))))))



That said, I would recommend using syntax parameters for break and continue.
They're cleaner, since they can be rebound by the user. Also, you can
use let/ec from (ice-9 control) instead of call/cc. It's more efficient
because it doesn't need to actually reify the whole environment, since
an escape continuation is upwards-only (it can be used inside the expression
to escape it, but it can't be used outside to reinstate its context).


(use-modules (ice-9 control))

(define-syntax-parameter break
   (lambda (sintax)
     (syntax-violation 'break "break outside of for/bc" sintax)))

(define-syntax-parameter continue
   (lambda (sintax)
     (syntax-violation 'continue "continue outside of for/bc" sintax)))

(define-syntax-rule (for/bc (init test increment) body body* ...)
   (begin
     init
     (let/ec escape
       (syntax-parameterize ((break (identifier-syntax (escape))))
         (let loop ()
           (when test
             (let/ec next
               (syntax-parameterize ((continue (identifier-syntax (next))))
                 body body* ...))
             increment
             (loop)))))))

(let ((i #f))
   (for/bc ((set! i 0) (< i 10) (set! i (1+ i)))
     (when (< i 5)
       continue)
     (when (> i 9)
       break)
     (display i)
     (newline)))




And here's an example showing the benefits of syntax parameters.
Add at the beginning of the code above:


(define-module (for)
   #:export (break continue for/bc))


In the same directory, put a file rename.scm containing:

(use-modules ((for)
               #:select ((break . for-break) continue for/bc))
              (srfi srfi-1) ; contains a break procedure
              (ice-9 receive))

(let ((i #f))
   (for/bc ((set! i 0) (< i 10) (set! i (1+ i)))
     (receive (before after)
       (break (lambda (x)
                (> x 5))
              (iota i))
       (when (pair? after)
         for-break)
       (display i))))



And run as

guile -L . rename.scm

As you can see, syntax parameters enable the code to use 'break'
for something else.

A final note: are you aware of the existence of 'do' in Scheme?
Most cases of a C for loop can be written elegantly using do.

https://www.gnu.org/software/guile/manual/html_node/while-do.html

Regards,
Jean




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

* Re: for with break and continue
  2022-09-04 10:43 ` Jean Abou Samra
@ 2022-09-04 12:00   ` Damien Mattei
  2022-09-04 12:40     ` Jean Abou Samra
  0 siblings, 1 reply; 7+ messages in thread
From: Damien Mattei @ 2022-09-04 12:00 UTC (permalink / raw)
  To: Jean Abou Samra; +Cc: guile-user

yes very good
then break si not overwritten, using module, i do not know if modules is
finally standardised in R6RS, and in guile?
a few problem with module i hope to fix it later but it works with your
example, not sure let/ec is standart?
i will continue later....
Damien

On Sun, Sep 4, 2022 at 12:44 PM Jean Abou Samra <jean@abou-samra.fr> wrote:

> Le 04/09/2022 à 11:54, Damien Mattei a écrit :
> > i try to make a for with break and continue the way C language do it, i
> > works with break but if i add a continue feature i then loose the break
> > feature, here is my code:
> > (define-syntax for/bc
> >
> >    (lambda (stx)
> >      (syntax-case stx ()
> >        ((kwd (init test incrmt) body ...)
> >
> >         (with-syntax
> > ((BREAK (datum->syntax #'kwd 'break)))
> >
> > #'(call/cc
> >    (lambda (escape)
> >      (let-syntax
> > ((BREAK (identifier-syntax (escape))))
> >        init
> >        (let loop ()
> > (when test
> >
> >        (with-syntax
> > ((CONTINUE (datum->syntax #'kwd 'continue)))
> >
> > #'(call/cc
> >   (lambda (next)
> >     (let-syntax
> > ((CONTINUE (identifier-syntax (next))))
> >       body ...)))
> >
> >        incrmt
> >        (loop))))))))))))
>
>
>
> The problem is with the meta level vs. the expanded output level. You have
> two nested levels of #' . This (with-syntax ((CONTINUE ...)) ...) is part
> of
> the expanded output, it doesn't run when your macro is expanded. The body
> of
> the (expanded) loop just returns a syntax object. That's not what you want.
> Here's a definition that works:
>
> (define-syntax for/bc
>    (lambda (stx)
>      (syntax-case stx ()
>        ((kwd (init test incrmt) body ...)
>         (with-syntax ((BREAK (datum->syntax #'kwd 'break))
>                       (CONTINUE (datum->syntax #'kwd 'continue)))
>           #'(call/cc
>              (lambda (escape)
>                (let-syntax ((BREAK (identifier-syntax (escape))))
>                  init
>                  (let loop ()
>                    (when test
>                      (call/cc
>                       (lambda (next)
>                         (let-syntax ((CONTINUE (identifier-syntax (next))))
>                           body ...)))
>                        incrmt
>                        (loop)))))))))))
>
> (let ((i #f))
>    (for/bc ((set! i 0) (< i 10) (set! i (1+ i)))
>      (when (< i 5)
>        continue)
>      (when (> i 9)
>        break)
>      (display i)
>      (newline)))
>
>
>
> You could also use quasisyntax (#` and #,) to get the same effect:
>
>
> (define-syntax for/bc
>    (lambda (stx)
>      (syntax-case stx ()
>        ((kwd (init test incrmt) body ...)
>         #`(call/cc
>            (lambda (escape)
>              (let-syntax ((#,(datum->syntax #'kwd 'break)
>                            (identifier-syntax (escape))))
>                init
>                (let loop ()
>                  (when test
>                    (call/cc
>                     (lambda (next)
>                       (let-syntax ((#,(datum->syntax #'kwd 'continue)
>                                     (identifier-syntax (next))))
>                         body ...)))
>                    incrmt
>                    (loop))))))))))
>
>
>
> That said, I would recommend using syntax parameters for break and
> continue.
> They're cleaner, since they can be rebound by the user. Also, you can
> use let/ec from (ice-9 control) instead of call/cc. It's more efficient
> because it doesn't need to actually reify the whole environment, since
> an escape continuation is upwards-only (it can be used inside the
> expression
> to escape it, but it can't be used outside to reinstate its context).
>
>
> (use-modules (ice-9 control))
>
> (define-syntax-parameter break
>    (lambda (sintax)
>      (syntax-violation 'break "break outside of for/bc" sintax)))
>
> (define-syntax-parameter continue
>    (lambda (sintax)
>      (syntax-violation 'continue "continue outside of for/bc" sintax)))
>
> (define-syntax-rule (for/bc (init test increment) body body* ...)
>    (begin
>      init
>      (let/ec escape
>        (syntax-parameterize ((break (identifier-syntax (escape))))
>          (let loop ()
>            (when test
>              (let/ec next
>                (syntax-parameterize ((continue (identifier-syntax (next))))
>                  body body* ...))
>              increment
>              (loop)))))))
>
> (let ((i #f))
>    (for/bc ((set! i 0) (< i 10) (set! i (1+ i)))
>      (when (< i 5)
>        continue)
>      (when (> i 9)
>        break)
>      (display i)
>      (newline)))
>
>
>
>
> And here's an example showing the benefits of syntax parameters.
> Add at the beginning of the code above:
>
>
> (define-module (for)
>    #:export (break continue for/bc))
>
>
> In the same directory, put a file rename.scm containing:
>
> (use-modules ((for)
>                #:select ((break . for-break) continue for/bc))
>               (srfi srfi-1) ; contains a break procedure
>               (ice-9 receive))
>
> (let ((i #f))
>    (for/bc ((set! i 0) (< i 10) (set! i (1+ i)))
>      (receive (before after)
>        (break (lambda (x)
>                 (> x 5))
>               (iota i))
>        (when (pair? after)
>          for-break)
>        (display i))))
>
>
>
> And run as
>
> guile -L . rename.scm
>
> As you can see, syntax parameters enable the code to use 'break'
> for something else.
>
> A final note: are you aware of the existence of 'do' in Scheme?
> Most cases of a C for loop can be written elegantly using do.
>
> https://www.gnu.org/software/guile/manual/html_node/while-do.html
>
> Regards,
> Jean
>
>


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

* Re: for with break and continue
  2022-09-04 12:00   ` Damien Mattei
@ 2022-09-04 12:40     ` Jean Abou Samra
  2022-09-04 14:41       ` Damien Mattei
  0 siblings, 1 reply; 7+ messages in thread
From: Jean Abou Samra @ 2022-09-04 12:40 UTC (permalink / raw)
  To: Damien Mattei; +Cc: guile-user



Le 04/09/2022 à 14:00, Damien Mattei a écrit :
> yes very good
> then break si not overwritten, using module, i do not know if modules 
> is finally standardised in R6RS, and in guile?



Guile supports R6RS libraries, but it's not the same as its traditional 
use-modules/define-module forms.

https://www.gnu.org/software/guile/manual/html_node/R6RS-Libraries.html

But you're going to have a much more pressing problem with 
standardization: syntax parameters are not standard. So you're a bit 
stuck there.



> a few problem with module i hope to fix it later but it works with 
> your example, not sure let/ec is standart?


let/ec is not standard, but exceptions are. See section 7 of the 
libraries document of R6RS:

http://www.r6rs.org/final/r6rs-lib.pdf

Best,
Jean




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

* Re: for with break and continue
  2022-09-04 12:40     ` Jean Abou Samra
@ 2022-09-04 14:41       ` Damien Mattei
  2022-09-05  0:42         ` Jean Abou Samra
  0 siblings, 1 reply; 7+ messages in thread
From: Damien Mattei @ 2022-09-04 14:41 UTC (permalink / raw)
  To: Jean Abou Samra; +Cc: guile-user

yes in fact a lot of function related to syntax (datum->syntax, etc) are
not in R6RS and R7RS-small,
i have to keep that in mind because i want to write a library that could be
portable between scheme implementation and that support curly-infix ,less
than a number of scheme that count with the fingers of an hand ,at the
end.... :-) but 'for was a disgression,i know 'while of guile, again not
standard...

Regards,
Damien

On Sun, Sep 4, 2022 at 2:40 PM Jean Abou Samra <jean@abou-samra.fr> wrote:

>
>
> Le 04/09/2022 à 14:00, Damien Mattei a écrit :
> > yes very good
> > then break si not overwritten, using module, i do not know if modules
> > is finally standardised in R6RS, and in guile?
>
>
>
> Guile supports R6RS libraries, but it's not the same as its traditional
> use-modules/define-module forms.
>
> https://www.gnu.org/software/guile/manual/html_node/R6RS-Libraries.html
>
> But you're going to have a much more pressing problem with
> standardization: syntax parameters are not standard. So you're a bit
> stuck there.
>
>
>
> > a few problem with module i hope to fix it later but it works with
> > your example, not sure let/ec is standart?
>
>
> let/ec is not standard, but exceptions are. See section 7 of the
> libraries document of R6RS:
>
> http://www.r6rs.org/final/r6rs-lib.pdf
>
> Best,
> Jean
>
>


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

* Re: for with break and continue
  2022-09-04 14:41       ` Damien Mattei
@ 2022-09-05  0:42         ` Jean Abou Samra
  2022-09-05  8:46           ` Damien Mattei
  0 siblings, 1 reply; 7+ messages in thread
From: Jean Abou Samra @ 2022-09-05  0:42 UTC (permalink / raw)
  To: Damien Mattei; +Cc: guile-user



Le 04/09/2022 à 16:41, Damien Mattei a écrit :
> yes in fact a lot of function related to syntax (datum->syntax, etc) 
> are not in R6RS and R7RS-small,


datum->syntax actually *is* R6RS, in the "libraries" document. See 
http://www.r6rs.org/final/r6rs-lib.pdf page 55.

(It is not in R7RS small, since R7RS small doesn't even have syntax-case.)


> i have to keep that in mind because i want to write a library that 
> could be portable between scheme implementation and that support 
> curly-infix ,less than a number of scheme that count with the fingers 
> of an hand ,at the end.... :-) but 'for was a disgression,i know 
> 'while of guile, again not standard...
>
> Regards,
> Damien
>
> On Sun, Sep 4, 2022 at 2:40 PM Jean Abou Samra <jean@abou-samra.fr> wrote:
>
>
>
>     Le 04/09/2022 à 14:00, Damien Mattei a écrit :
>     > yes very good
>     > then break si not overwritten, using module, i do not know if
>     modules
>     > is finally standardised in R6RS, and in guile?
>
>
>
>     Guile supports R6RS libraries, but it's not the same as its
>     traditional
>     use-modules/define-module forms.
>
>     https://www.gnu.org/software/guile/manual/html_node/R6RS-Libraries.html
>
>     But you're going to have a much more pressing problem with
>     standardization: syntax parameters are not standard. So you're a bit
>     stuck there.
>
>
>
>     > a few problem with module i hope to fix it later but it works with
>     > your example, not sure let/ec is standart?
>
>
>     let/ec is not standard, but exceptions are. See section 7 of the
>     libraries document of R6RS:
>
>     http://www.r6rs.org/final/r6rs-lib.pdf
>
>     Best,
>     Jean
>




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

* Re: for with break and continue
  2022-09-05  0:42         ` Jean Abou Samra
@ 2022-09-05  8:46           ` Damien Mattei
  0 siblings, 0 replies; 7+ messages in thread
From: Damien Mattei @ 2022-09-05  8:46 UTC (permalink / raw)
  To: Jean Abou Samra; +Cc: guile-user

very interesting.
Finally is our functions,at least one, for/bc compatible with R6RS? i can
not exactly figure it exactly, i see at leats identifier-syntax not in the
library index:
http://www.r6rs.org/final/html/r6rs-lib/r6rs-lib-Z-H-21.html#node_index_start
one day i will have to read the Dybvig article to understand all
that.Perhaps in a near future. ;-)
Damien


On Mon, Sep 5, 2022 at 2:42 AM Jean Abou Samra <jean@abou-samra.fr> wrote:

>
>
> Le 04/09/2022 à 16:41, Damien Mattei a écrit :
> > yes in fact a lot of function related to syntax (datum->syntax, etc)
> > are not in R6RS and R7RS-small,
>
>
> datum->syntax actually *is* R6RS, in the "libraries" document. See
> http://www.r6rs.org/final/r6rs-lib.pdf page 55.
>
> (It is not in R7RS small, since R7RS small doesn't even have syntax-case.)
>
>
> > i have to keep that in mind because i want to write a library that
> > could be portable between scheme implementation and that support
> > curly-infix ,less than a number of scheme that count with the fingers
> > of an hand ,at the end.... :-) but 'for was a disgression,i know
> > 'while of guile, again not standard...
> >
> > Regards,
> > Damien
> >
> > On Sun, Sep 4, 2022 at 2:40 PM Jean Abou Samra <jean@abou-samra.fr>
> wrote:
> >
> >
> >
> >     Le 04/09/2022 à 14:00, Damien Mattei a écrit :
> >     > yes very good
> >     > then break si not overwritten, using module, i do not know if
> >     modules
> >     > is finally standardised in R6RS, and in guile?
> >
> >
> >
> >     Guile supports R6RS libraries, but it's not the same as its
> >     traditional
> >     use-modules/define-module forms.
> >
> >
> https://www.gnu.org/software/guile/manual/html_node/R6RS-Libraries.html
> >
> >     But you're going to have a much more pressing problem with
> >     standardization: syntax parameters are not standard. So you're a bit
> >     stuck there.
> >
> >
> >
> >     > a few problem with module i hope to fix it later but it works with
> >     > your example, not sure let/ec is standart?
> >
> >
> >     let/ec is not standard, but exceptions are. See section 7 of the
> >     libraries document of R6RS:
> >
> >     http://www.r6rs.org/final/r6rs-lib.pdf
> >
> >     Best,
> >     Jean
> >
>
>


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

end of thread, other threads:[~2022-09-05  8:46 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-04  9:54 for with break and continue Damien Mattei
2022-09-04 10:43 ` Jean Abou Samra
2022-09-04 12:00   ` Damien Mattei
2022-09-04 12:40     ` Jean Abou Samra
2022-09-04 14:41       ` Damien Mattei
2022-09-05  0:42         ` Jean Abou Samra
2022-09-05  8:46           ` Damien Mattei

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