From: Sunnan
Subject: An idea for making define-macro more convenient to use
Date: 
Message-ID: <AbuTd.131258$dP1.470494@newsc.telia.net>
How about making a version of define-macro (with another name) where 
variables introdued are in their own separate namespace (for a broad 
enough definition of the word "namespace"), and had to be explicitly 
converted if we wanted to expose them?

E.g. in my-or (from _Teach Yourself Scheme_), "temp" would be in it's 
own "macro-namespace" so that the following would be ok:

(define-macro* my-or
   (lambda (x y)
     `(let ((temp ,x))
        (if temp temp ,y))))

This could be a wrapper for using gensyms, so that it would expand to:

(define-macro my-or
   (lambda (x y)
     (let ((temp (gensym)))
       `(let ((,temp ,x))
          (if ,temp ,temp ,y)))))

If we wanted to deliberately introduce variables, we could wrap them in 
a function to "convert" them from the "macro-namespace":
(define-macro* my-weird-or
   (lambda (x y)
     `(let (((capture temp) ,x))
         (if temp temp ,y))))

could expand to:
(define-macro my-weird-or
    (lambda (x y)
      `(let ((temp ,x))
          (if temp temp ,y))))

From: Kaz Kylheku
Subject: Re: An idea for making define-macro more convenient to use
Date: 
Message-ID: <1109302073.058983.132710@o13g2000cwo.googlegroups.com>
Sunnan wrote:
> How about making a version of define-macro (with another name) where

You want comp.lang.scheme only, not comp.lang.lisp. [Followup-to set]

> variables introdued are in their own separate namespace (for a broad
> enough definition of the word "namespace"), and had to be explicitly
> converted if we wanted to expose them?

Scheme has hygienic macros already. Take a look at syntax-rules. You
are many years too late with this.

> E.g. in my-or (from _Teach Yourself Scheme_), "temp" would be in it's

> own "macro-namespace" so that the following would be ok:
>
> (define-macro* my-or
>    (lambda (x y)
>      `(let ((temp ,x))
>         (if temp temp ,y))))

Actually, true hygienic macro proponents would also want something like
this to work:

 (let ((temp <whatever>))
   (define-macro (x y)
     `(if temp temp ,y)))

The occurences of temp introduced in the template are considered to
refer to the binding introduced in the surrounding let. But any
occurences of the symbol temp introduced as ,y material will not
resolve to that binding; they will, resolve to whatever binding the
user has set up around the use of the macro.
From: Taylor Campbell
Subject: Re: An idea for making define-macro more convenient to use
Date: 
Message-ID: <2005022516143916807%campbell@bloodandcoffeenet>
On 2005-02-24 19:20:48 -0500, Sunnan <······@handgranat.org> said:

> How about making a version of define-macro (with another name) where 
> variables introdued are in their own separate namespace (for a broad 
> enough definition of the word "namespace"), and had to be explicitly 
> converted if we wanted to expose them?

Hmmmm, so you want a special namespace for these names?  Let's call
that a 'syntactic environment,' since it has to do with environments as
used in syntactic manipulation.  Now, you want output that the macro
generates to use the macro's own syntactic environment, and output that
was in the input to use the input's syntactic environment?  Perhaps we
could say that certain forms are 'closed' in a syntactic environment,
sort of like how procedures are closed in a lexical environment.  We
could call these things 'syntactic closures.'

In fact, this is the major alternative to the very complicated hygiene
algorithm when macros started being discussed for standardization in
Scheme in the late '80s.  I suggest that you read Bawden & Rees's 1988
paper 'Syntactic Closures':

  <http://www.bloodandcoffee.net/campbell/papers/bawden88synclo.pdf>

It is just as simple as regular list manipulation, only certain forms
are annotated with syntactic environments to control how names are
mapped to denotations.  It requires no gruesomely complex extension as
SYNTAX-CASE or anything.  Though the original 1988 proposal was unable
to implement SYNTAX-RULES (or EXTEND-SYNTAX, as it was called at that
time), it was extended by Chris Hanson in such a way as to make it
possible to implement the 'explicit renaming' macro system, which is
the basis for most SYNTAX-RULES implementations that don't use the
hygiene algorithm.  Explicit renaming is described in a 1991 paper by
Will Clinger:

  <http://www.bloodandcoffee.net/campbell/papers/clinger91exrename.pdf>

> E.g. in my-or (from _Teach Yourself Scheme_), "temp" would be in it's 
> own "macro-namespace" so that the following would be ok:
> 
> (define-macro* my-or
>    (lambda (x y)
>      `(let ((temp ,x))
>         (if temp temp ,y))))

This would be, in syntactic closures:

  (define-syntax my-or
    (sc-macro-transformer
     (lambda (form env)
       (let ((x (close-syntax (cadr  form) env))
             (y (close-syntax (caddr form) env)))
         `(LET ((TEMP ,x))
            (IF TEMP TEMP ,x))))))

ENV represents the syntactic environment of MY-OR's use.

> This could be a wrapper for using gensyms, so that it would expand to:
> 
> (define-macro my-or
>    (lambda (x y)
>      (let ((temp (gensym)))
>        `(let ((,temp ,x))
>           (if ,temp ,temp ,y)))))

There need actually be no 'expansion' of transformer procedures in the
syntactic closures system.  It's very simple: it just introduces a new
form of transformers and a few procedures (CLOSE-SYNTAX, IDENTIFIER?,
CAPTURE-SYNTACTIC-ENVIRONMENT, MAKE-SYNTACTIC-CLOSURE, and
IDENTIFIER=?).

> If we wanted to deliberately introduce variables, we could wrap them in 
> a function to "convert" them from the "macro-namespace":
> (define-macro* my-weird-or
>    (lambda (x y)
>      `(let (((capture temp) ,x))
>          (if temp temp ,y))))

This, too, is easy to do with syntactic closures.  We just list TEMP as
a 'free name' in the Y form:

  (define-syntax my-weird-or
    (sc-macro-transformer
     (lambda (form env)
       (let ((x (close-syntax (cadr form) env))
             (y (make-syntactic-closure env '(TEMP) (caddr form))))
         `(LET ((TEMP ,x))
            (IF TEMP TEMP ,y))))))

Names in Y get their denotations in ENV, except for the name TEMP,
whose denotation is taken from the surrounding context.

> could expand to:
> (define-macro my-weird-or
>     (lambda (x y)
>       `(let ((temp ,x))
>           (if temp temp ,y))))

And, again, there's no strange expansion of procedures or anything in
syntactic closures.
From: Display Name
Subject: Re: An idea for making define-macro more convenient to use
Date: 
Message-ID: <D9PTd.23195$%U2.17048@lakeread01>
"Taylor Campbell" <········@bloodandcoffee.net> wrote

> In fact, this is the major alternative to the very complicated hygiene
> algorithm when macros started being discussed for standardization in
> Scheme in the late '80s.  I suggest that you read Bawden & Rees's 1988
> paper 'Syntactic Closures':

Bawden and Reese's system is indeed simple, but I don't find Hanson's
elaboration simple.  I have not read the reference implementation, but
at least the paper does not quite make the semantics clear to me.  In his
example:
(define-syntax loop-until
  (transformer
   (lambda (exp env)
     (let ((id (cadr exp))
           (init (caddr exp))
           (test (cadddr exp))
           (return (cadddr (cdr exp)))
           (step (cadddr (cddr exp)))
           (close
            (lambda (exp free)
              (make-syntactic-closure env free exp))))
       `(letrec ((loop
                  ,(capture-syntactic-environment
                    (lambda (env)
                      `(lambda (,id)
                         (,(make-syntactic-closure env '() `if)
                          ,(close test (list id))
                          ,(close return (list id))
                          (,(make-syntactic-closure env '()
                                                    `loop)
                           ,(close step (list id)))))))))
          (loop ,(close init '())))))))what exactly does
CAPTURE-SYNTACTIC-ENVIRONMENT do?  The normal semantics of quasiquote allows
the transformation   `(letrec ((loop ,(capture-syntactic-environment ....)
....  ==> (let ((c (capture-syntactic-environment ....)))        `(letrec
((loop ,c)) ...)but the right hand side would presumably capture the root
transformerenvironment, which is not what was intended in the example.  So
it seems that we are "substantially changing what backquote does", perhaps
in a way that is just as complex as SYNTAX-CASE (although I might be wayoff
base).Also, what do syntactic closures have to say about nested orrecursive
macros - does every pass create a new transformer environment for the same
macro or not?  With syntax-rules, there are examples wherethis is essential
for hygiene.  Again, reading the informal Hanson specification does not
clear that up for me.  RegardsAndre
From: Display Name
Subject: Re: An idea for making define-macro more convenient to use
Date: 
Message-ID: <3ePTd.23197$%U2.9957@lakeread01>
Sorry about the bad formatting.  Here's another try:

> "Taylor Campbell" <········@bloodandcoffee.net> wrote
>
> > In fact, this is the major alternative to the very complicated hygiene
> > algorithm when macros started being discussed for standardization in
> > Scheme in the late '80s.  I suggest that you read Bawden & Rees's 1988
> > paper 'Syntactic Closures':
>
Bawden and Reese's system is indeed simple, but I don't find Hanson's
elaboration simple.  I have not read the reference implementation, but
at least the paper does not quite make the semantics clear to me.  In his
example:

(define-syntax loop-until
  (transformer
   (lambda (exp env)
      (let ((id (cadr exp))
            (init (caddr exp))
            (test (cadddr exp))
            (return (cadddr (cdr exp)))
            (step (cadddr (cddr exp)))
            (close
             (lambda (exp free)
               (make-syntactic-closure env free exp))))
        `(letrec ((loop
                   ,(capture-syntactic-environment
                     (lambda (env)
                       `(lambda (,id)
                          (,(make-syntactic-closure env '() `if)
                           ,(close test (list id))
                           ,(close return (list id))
                           (,(make-syntactic-closure env '()
                                                     `loop)
                            ,(close step (list id)))))))))
           (loop ,(close init '())))))))

what exactly does
CAPTURE-SYNTACTIC-ENVIRONMENT do?  The normal semantics of quasiquote allows
the transformation

`(letrec ((loop ,(capture-syntactic-environment ....)
   ....)
   ==> (let ((c (capture-syntactic-environment ....)))
                 `(letrec
                          ((loop ,c)) ...)

but the right hand side would presumably capture the root
transformerenvironment, which is not what was intended in the example.  So
it seems that we are "substantially changing what backquote does", perhaps
in a way that is just as complex as SYNTAX-CASE (although I might be way
off).

Also, what do syntactic closures have to say about nested or recursive
macros - does every pass create a new transformer environment for the same
macro or not?  With syntax-rules, there are examples wherethis is essential
for hygiene.  Again, reading the informal Hanson specification does not
clear that up for me.

Regards
Andre

>
From: Sunnan
Subject: Re: An idea for making define-macro more convenient to use
Date: 
Message-ID: <%5PTd.18137$d5.143019@newsb.telia.net>
Thanks for replying, I set follow-up to cls only since I've been 
reminded that cll is mainly for common lisp. (Where do "generic lisp" 
issues go?)

Taylor Campbell wrote:
> Hmmmm, so you want a special namespace for these names?
 >
> Let's call
> that a 'syntactic environment,' since it has to do with environments as
> used in syntactic manipulation.  Now, you want output that the macro
> generates to use the macro's own syntactic environment, and output that
> was in the input to use the input's syntactic environment?  Perhaps we
> could say that certain forms are 'closed' in a syntactic environment,
> sort of like how procedures are closed in a lexical environment.  We
> could call these things 'syntactic closures.'

Another way to do it would be by generating unique symbols particular to 
that macroexpansion.

> There need actually be no 'expansion' of transformer procedures in the
> syntactic closures system.

Is that a good thing? Part of the percieved advantage with macros is 
that it moves some of the work to compile time.

I'm sorry if I misunderstood you.
From: Kent M Pitman
Subject: Re: An idea for making define-macro more convenient to use
Date: 
Message-ID: <uy8dcrtub.fsf@nhplace.com>
[ Responding only to comp.lang.lisp.
  http://www.nhplace.com/kent/PFAQ/cross-posting.html ]

Sunnan <······@handgranat.org> writes:

> How about making a version of define-macro (with another name) where
> variables introdued are in their own separate namespace (for a broad
> enough definition of the word "namespace"), and had to be explicitly
> converted if we wanted to expose them?
> 
> E.g. in my-or (from _Teach Yourself Scheme_), "temp" would be in it's
> own "macro-namespace" so that the following would be ok:
> 
> (define-macro* my-or
>    (lambda (x y)
>      `(let ((temp ,x))
>         (if temp temp ,y))))
> 
> This could be a wrapper for using gensyms, so that it would expand to:
> 
> (define-macro my-or
>    (lambda (x y)
>      (let ((temp (gensym)))
>        `(let ((,temp ,x))
>           (if ,temp ,temp ,y)))))

Symbolics Lisp had ONCE-ONLY, which was cool but didn't trust the compiler
to do the right thing on its own, so was unnecessarily complicated in 
design and implementation; LispWorks has both REBINDING and WITH-UNIQUE-NAMES
(a variant of ONCE-ONLY), which work in a quite natural and general way
to accomplish the kind of thing you want for CL.

e.g.,

  (defmacro my-or (x y)
    (with-unique-names (temp)
      `(let ((,temp ,x))
         (if ,temp ,temp ,y))))

gets a gensym in temp and does what you want.

Furthermore, if you want to evaluate something over and over:

  (defmacro max-cubed (x y)
    (rebinding (x y)
      `(max (* ,x ,x ,x) (* ,y ,y ,y))))

which is essentially like having written:

  (defmacro max-cubed (x y)
    (let ((x-init x)
          (y-init y)
          (x (gensym "X"))
          (y (gensym "Y")))
      `(let ((,x ,x-init)
             (,y ,y-init))
         (max (* ,x ,x ,x)
              (* ,y ,y ,y)))))
From: Rob Warnock
Subject: Re: An idea for making define-macro more convenient to use
Date: 
Message-ID: <pNydnV169-boNLzfRVn-tQ@speakeasy.net>
Kent M Pitman  <······@nhplace.com> wrote:
+---------------
| Symbolics Lisp had ONCE-ONLY, which was cool but didn't trust the compiler
| to do the right thing on its own, so was unnecessarily complicated in 
| design and implementation; LispWorks has both REBINDING and WITH-UNIQUE-NAMES
| (a variant of ONCE-ONLY), which work in a quite natural and general way
| to accomplish the kind of thing you want for CL.
+---------------

CMUCL has an EXT:ONCE-ONLY which may do the same thing. The docstring:

  "Once-Only ({(Var Value-Expression)}*) Form*
  Create a Let* which evaluates each Value-Expression, binding a temporary
  variable to the result, and wrapping the Let* around the result of the
  evaluation of Body.  Within the body, each Var is bound to the corresponding
  temporary variable."


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607