unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
From: Damien Mattei <damien.mattei@gmail.com>
To: Jean Abou Samra <jean@abou-samra.fr>
Cc: guile-user <guile-user@gnu.org>
Subject: Re: for with break and continue
Date: Sun, 4 Sep 2022 14:00:37 +0200	[thread overview]
Message-ID: <CADEOadfz_Qq_Dc-8kYZgqNpxa4axwrq6x5x=p_f6Hxiji6XPPg@mail.gmail.com> (raw)
In-Reply-To: <89d7a30c-9a36-00b9-49d1-a28b0d776ce3@abou-samra.fr>

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	other threads:[~2022-09-04 12:00 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
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

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='CADEOadfz_Qq_Dc-8kYZgqNpxa4axwrq6x5x=p_f6Hxiji6XPPg@mail.gmail.com' \
    --to=damien.mattei@gmail.com \
    --cc=guile-user@gnu.org \
    --cc=jean@abou-samra.fr \
    /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).