guile-user
[Top][All Lists]
Advanced

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

Re: return macro


From: Stefan Israelsson Tampe
Subject: Re: return macro
Date: Thu, 30 Sep 2021 11:18:23 +0200

used write a lambda using it prepending a ,opt and you will see what the
macros expand to like

,opt (lambda (x) (let/ec ret (when x (ret x)) (+ x x)))

On Thu, Sep 30, 2021 at 10:46 AM Damien Mattei <damien.mattei@gmail.com>
wrote:

> i do not remember well the technic of this commented code, in this case
> note that it is 'break' keyword that cause the current continuation being
> called and escaping from the loop to the continuing code...
> there is no 'return' here but 'break'.
> Damien
>
> On Thu, Sep 30, 2021 at 5:38 AM adriano <randomlooser@riseup.net> wrote:
>
> > Il giorno lun, 28/06/2021 alle 03.15 +0200, Taylan Kammer ha scritto:
> > > On 28.06.2021 01:10, Damien Mattei wrote:
> > > > hi,
> > > >
> > > > i wanted to create a macro that is used like a function definition
> > > > and
> > > > allow return using call/cc:
> > > >
> > > > (define-syntax def
> > > > (syntax-rules (return)
> > > > ((_ (name args ...) body body* ...)
> > > > (define name (lambda (args ...)
> > > > (call/cc (lambda (return) body body* ...)))))
> > > > ((_ name expr) (define name expr))))
> > > >
> > > > unfortunaly i got error:
> > > >
> > > > scheme@(guile-user)> (def (test x) (cond ((= x 3) 7) ((= x 2)
> > > > (return 5))
> > > > (else 3)))
> > > > ;;; <stdin>:2:42: warning: possibly unbound variable `return'
> > > > scheme@(guile-user)> (test 2)
> > > > ice-9/boot-9.scm:1685:16: In procedure raise-exception:
> > > > Unbound variable: return
> > > >
> > > >
> > > > any idea?
> > >
> > > Hi Damien,
> > >
> > > This is because of the "hygiene" rule of Scheme, where the notion of
> > > "lexical
> > > scope" is taken very seriously: for an identifier to be bound, it
> > > must be
> > > visible in the lexical (textual) surroundings where it has been
> > > bound.
> > >
> > > So for instance, in the following example code:
> > >
> > >   (def (test x)
> > >     (cond
> > >      ((= x 3) (return 7))
> > >      ((= x 2) (return 5))))
> > >
> > > We can't see a binding for "return" anywhere in the text, therefore
> > > it cannot
> > > be bound.
> > >
> > > This is good "default" behavior because it makes code more flexible
> > > and easier
> > > to understand.
> > >
> > > An easy way of overcoming this issue is to let the user explicitly
> > > name the
> > > return identifier however they like:
> > >
> > >   (define-syntax def
> > >     (syntax-rules ()
> > >       ((_ (name ret arg ...) body body* ...)
> > >        (define (name arg ...)
> > >          (call/cc (lambda (ret) body body* ...))))))
> > >
> > > Now you could define:
> > >
> > >   (def (test return x)
> > >     (cond
> > >      ((= x 3) (return 7))
> > >      ((= x 2) (return 5))))
> > >
> > > Or for instance:
> > >
> > >   (def (test blubba x)
> > >     (cond
> > >      ((= x 3) (blubba 7))
> > >      ((= x 2) (blubba 5))))
> > >
> > > However, sometimes you're sure that you want to make an implicit
> > > binding for
> > > an identifier, and for those cases you need to write an "unhygienic"
> > > macro
> > > which can be achieved with the more complex macro system "syntax-
> > > case".
> > >
> > > Here's how your desired macro could be defined.  I will use
> > > identifiers like
> > > "<foo>" just for easier readability; they don't have any special
> > > meaning:
> > >
> > >   (define-syntax def
> > >     (lambda (stx)
> > >       (syntax-case stx ()
> > >         ((_ (<name> <arg> ...) <body> <body>* ...)
> > >          (let ((ret-id (datum->syntax stx 'return)))
> > >            #`(define (<name> <arg> ...)
> > >                (call/cc (lambda (#,ret-id) <body> <body>* ...))))))))
> > >
> > > There's a few things here to take note of:
> > >
> > > - Unlike with syntax-rules, the syntax-case is contained in a lambda
> > > which
> > >   takes a single argument: a "syntax object" which is passed to
> > > syntax-case
> > >
> > > - Unlike with syntax-rules, the "body" of the macro (where it begins
> > > with a
> > >   'let') is not immediately part of the generated code; that 'let' is
> > > actually
> > >   executed during compile-time.  The body of the macro must result in
> > > an
> > >   object of the type "syntax object" that represents the generated
> > > code.
> > >
> > > - You see that I define a variable called "ret-id" which I bind to
> > > the result
> > >   of the expression:
> > >
> > >     (datum->syntax stx 'return)
> > >
> > >   which means "create a syntax object in the same lexical environment
> > > as stx,
> > >   and is represented by the symbol 'return'."
> > >
> > > - The actual code generation begins within the #`(...) which is a
> > > shorthand
> > >   for (quasisyntax (...)) just like '(...) is short for (quote
> > > (...)).  The
> > >   result of a quasisyntax expression is a syntax object.  Basically,
> > > it's the
> > >   most convenient way of creating a syntax object, but like syntax-
> > > rules it's
> > >   also hygienic by default and you need to insert "unhygienic" syntax
> > > objects
> > >   into it explicitly.
> > >
> > > - Within the quasisyntax, I use #,ret-id which is short for (unsyntax
> > > ret-id)
> > >   to inject the unhygienic syntax object that holds the symbol
> > > 'return' into
> > >   the generated code.
> > >
> > > For someone used to macros in the Common Lisp or Elisp style, this
> > > may seem
> > > over-complicated.  It's the cost of the "hygienic by default"
> > > behavior.
> > >
> > > By the way I assume that you're just toying around with the language
> > > to learn.
> > > If you were thinking of using a 'def' macro like this in real code, I
> > > would
> > > discourage it because there's already a built-in mechanism that
> > > allows the
> > > programmer something very similar, called 'let/ec':
> > >
> > >   (import (ice-9 control))
> > >
> > >   (define (test x)
> > >     (let/ec return
> > >       (cond
> > >         ((= x 3) (return 7))
> > >         ((= x 2) (return 5)))))
> >
> >
> >
> > What does this return (defined with let/ec) do ?
> >
> > In the orevious versions I could see the call to call/cc so I could
> > (somewhat) figure out the "jump" imlpied by calling return
> >
> > But in this last case, where is the return behaviour defined ?
> >
> >
> >
> >
>


reply via email to

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