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