guile-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: for with break and continue


From: Damien Mattei
Subject: Re: for with break and continue
Date: Sun, 4 Sep 2022 14:00:37 +0200

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


reply via email to

[Prev in Thread] Current Thread [Next in Thread]