From: Ken Tilton
Subject: What's up with Scheme macros?
Date: 
Message-ID: <47b16aec$0$15172$607ed4bc@cv.net>
While trying to explain my irrational prejudice against Scheme macros I 
got curious as to why I hated them, so I googled up this:

   http://www.xs4all.nl/~hipster/lib/scheme/gauche/define-syntax-primer.txt

Boys and girls, that is almost eleven thousand words long!!!!!

I see the problem, they have this whole pattern-matching syntax-rules 
language moving from source input to output. I have done (and am 
supposed to be doing) enough Prolog to realize Scheme macro writers must 
be way smarter than me. But... why? No, not why are they smarter. Why do 
they have to be smarter? What was wrong with treating the source as an 
ordinary tree of data and just whinging it about with Scheme itself to 
produce the output? Please restrict yourself to one or more of these 
answers:

1. The hygiene made us do it.

2. We actually thought it would be way cool and super powerful.

3. We were embarrassd by the small size of the standard and decided to 
make it up in the macro language

4. Other _____________________

Jes curious,

kenny


-- 
http://smuglispweeny.blogspot.com/
http://www.theoryyalgebra.com/

"In the morning, hear the Way;
  in the evening, die content!"
                     -- Confucius

From: Shiro Kawai
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <b43de108-134f-4b4c-bb63-474693eca5c8@i12g2000prf.googlegroups.com>
I use both (CL and Scheme) at work but more inclined to Scheme.
And I do have a mixed feeling about the Scheme macros.

Ken Tilton <···········@optonline.net> wrote:
> 1. The hygiene made us do it.

If I need to pick one from the first three, probably this is it.

Theoretically, hygiene has nothing to do with pattern matching
sublanguage.
The pattern matching part is for the convenience and efficiency, if
I understand correctly.  To realize hygiene, every identifier has to
carry the syntactic context, which is added or removed in every macro
expansion.

It would be very inefficient to do that context handling
eagerly if the macro's input form is huge S-expr but the macro
expander
only shuffles its toplevel elements, so you want to do the context
handling lazily---that is, instead of applying the context to every
leaf
of the S-expr, you just feed a tuple of <S-expr, Context> to the macro
expander, which "peels" off the context on demand (e.g. <(a (b c)),
Context>
is transfomed to (<a, Context> <(b c), Context>) if the expander needs
to see the toplevel elements.)  Because of this tupling, you cannot
use
ordinary car/cdr to decompose the input.

The reason I have a mixed feeling is that I do like hygiene (it is
cool
that an exported macro of my module foo expands into a form that
inserts
the reference to the foo's internal macros/procedures and it just
works.
I'd use package prefix in CL, but I feel it's like hack.) but carrying
pattern language is... say, too heavy.   Lots of smart people have
tackled
this problem so there may not be the way to avoid that, but I hope
otherwise.

For the meantime, I use both legacy macros and hygienic marcos in my
Scheme code at work; legacy macros are handy if you have total control
over the source so that nobody will step on your toe or vice versa.
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <70054fc1-d06b-484a-ba4d-78874d9122e1@d21g2000prf.googlegroups.com>
On Feb 12, 5:14 am, Shiro Kawai <···········@gmail.com> wrote:

> It would be very inefficient to do that context handling
> eagerly if the macro's input form is huge S-expr but the macro
> expander
> only shuffles its toplevel elements, so you want to do the context
> handling lazily---that is, instead of applying the context to every
> leaf
> of the S-expr, you just feed a tuple of <S-expr, Context> to the macro
> expander, which "peels" off the context on demand (e.g. <(a (b c)),
> Context>
> is transfomed to (<a, Context> <(b c), Context>) if the expander needs
> to see the toplevel elements.)  Because of this tupling, you cannot
> use
> ordinary car/cdr to decompose the input.

That is not accurate, but the misconception is understandable given
the language of R6RS.

For example, the explicit renaming system can be
implemented with linear complexity with ordinary s-expressions that
are
decomposable using car, cdr, etc.  The same is true for syntax-case.
For example, my (Andre van Tonder's) syntax-case expander uses an
eager
algorithm based on a variant of explicit renaming and using ordinary
s-expressions decomposable using car/cdr.  Thus, syntax-case can be
viewed as a convenience layer on top of explicit renaming.
Explicit renaming is really quite simple.  See
http://groups.google.com/group/comp.lang.scheme/msg/a4817ec9ffcccf39

I was disappointed that the R6RS editors decided to describe the lazy
algorithm in the R6RS standard, when a simple declarative description
of
hygiene/referential transparency as in R5RS would have sufficed.
Instead they chose to describe, as part of the standard, a specific,
non-unique implementation strategy, in fact probably the most
complicated implementation strategy anyone has bothered to
come up with to date, virtually ensuring that hardly anyone will
understand the document.  I don't follow it, and I'm an implementor!
From: Shiro Kawai
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <45a0b269-818c-40a0-8377-6bed424cb8f1@q77g2000hsh.googlegroups.com>
············@yahoo.com wrote:
> That is not accurate, but the misconception is understandable given
> the language of R6RS.
>
> For example, the explicit renaming system can be
> implemented with linear complexity with ordinary s-expressions that
> are
> decomposable using car, cdr, etc.  The same is true for syntax-case.
> For example, my (Andre van Tonder's) syntax-case expander uses an
> eager
> algorithm based on a variant of explicit renaming and using ordinary
> s-expressions decomposable using car/cdr.  Thus, syntax-case can be
> viewed as a convenience layer on top of explicit renaming.
> Explicit renaming is really quite simple.  Seehttp://groups.google.com/group/comp.lang.scheme/msg/a4817ec9ffcccf39

Aha!  I've seen the explicit renaming expander but have never looked
at
it closely.  Now I read the articles and found it made a lot of sense,
and it feels more Scheme-way to me.  I'll give it a shot.  Thanks!
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <129c431c-1741-46f9-8846-3cdd543a3605@c4g2000hsg.googlegroups.com>
On Feb 12, 4:46 am, Ken Tilton <···········@optonline.net> wrote:

> I see the problem, they have this whole pattern-matching syntax-rules
> language moving from source input to output. I have done (and am
> supposed to be doing) enough Prolog to realize Scheme macro writers must
> be way smarter than me. But... why? No, not why are they smarter. Why do
> they have to be smarter? What was wrong with treating the source as an
> ordinary tree of data and just whinging it about with Scheme itself to
> produce the output?

Nothing is wrong with your suggestion.  Here is a simple macro
that will work in one of the R6RS reference implementations.

   (define-syntax swap!
     (lambda (form)
       (let ((a (cadr  form))
             (b (caddr form)))
         #`(let ((temp #,a))
             (set! #,a #,b)
             (set! #,b temp))))))

It is almost identical to the corresponding defmacro, except that
you use #` and #, instead of ` and ,.  Also, no gensym is necessary.
You can think, as a fisrt approximation, of #` as automatically
inserting the necessary gensyms for you.

Andre
From: Raffael Cavallaro
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <2008021212313616807-raffaelcavallaro@pasdespamsilvousplaitmaccom>
On 2008-02-12 11:26:54 -0500, ············@yahoo.com said:

> Nothing is wrong with your suggestion.  Here is a simple macro
> that will work in one of the R6RS reference implementations.
> 
>    (define-syntax swap!
>      (lambda (form)
>        (let ((a (cadr  form))
>              (b (caddr form)))
>          #`(let ((temp #,a))
>              (set! #,a #,b)
>              (set! #,b temp))))))
> 
> It is almost identical to the corresponding defmacro, except that
> you use #` and #, instead of ` and ,.  Also, no gensym is necessary.
> You can think, as a fisrt approximation, of #` as automatically
> inserting the necessary gensyms for you.

Not that I doubt the power of your system Andre, but could you show us 
a simple example of intentional capture inside a #` form?
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <a133f807-79f9-4a82-9ca3-92b6cdb45226@v17g2000hsa.googlegroups.com>
On Feb 12, 12:31 pm, Raffael Cavallaro <················@pas-d'espam-
s'il-vous-plait-mac.com> wrote:

> Not that I doubt the power of your system Andre, but could you show us
> a simple example of intentional capture inside a #` form?

  (define-syntax if-it
    (lambda (form)
      (let ((it (datum->syntax (car form) 'it)))
        #`(let ((,it ,(cadr form)))
           (if #,it
               #,(caddr form)
               #,(cadddr form))))))

DATUM->SYNTAX overrides hygiene by creating the identifier IT as if
it
appeared in the source at the position of (CAR FORM), i.e., the IF-IT
at the usage site of the macro.  You may think of this, very roughly,
as a standard way of making an identifier that is not affected by the
automatic gensym that would otherwise be applied by #`.

This is slightly longer than the defmacro way, but macros that
capture
are usually a minority.  Most defmacros can be trivially converted
to Scheme hygienic macros (in this R6RS reference implementation)
by omitting gensyms and putting #s in front of the `s,'s, and ,s
and would therefore be shortened rather than lengthened.

Unfortunately this is not true for all implementations of R6RS Scheme
macros.  Some unfortunately do not represent code as s-expressions
and rely on pattern matching to decompose their input.
While there are reasons for their design choice, I think it very
unfortunately obscures the fact that pattern matching is absolutely
orthogonal to - and unnecessary for - the hygiene mechanism.  As a
result,
people like the OP get the impression that hygiene is more
complicated
than it really is, and cannot entirely be blamed for giving
up in disgust.

Andre
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <a165139d-2420-4e3f-9793-630cc0ff0301@e25g2000prg.googlegroups.com>
On Feb 12, 2:07 pm, ············@yahoo.com wrote:

>   (define-syntax if-it
>     (lambda (form)
>       (let ((it (datum->syntax (car form) 'it)))
>         #`(let ((,it ,(cadr form)))
>            (if #,it
>                #,(caddr form)
>                #,(cadddr form))))))


Sorry.  I meant:

   (define-syntax if-it
     (lambda (form)
       (let ((it (datum->syntax (car form) 'it)))
         #`(let ((#,it #,(cadr form)))
            (if #,it
                #,(caddr form)
                #,(cadddr form))))))

Andre
From: Raffael Cavallaro
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <2008021318304516807-raffaelcavallaro@pasdespamsilvousplaitmaccom>
On 2008-02-12 14:37:54 -0500, ············@yahoo.com said:

> Sorry.  I meant:
> 
>    (define-syntax if-it
>      (lambda (form)
>        (let ((it (datum->syntax (car form) 'it)))
>          #`(let ((#,it #,(cadr form)))
>             (if #,it
>                 #,(caddr form)
>                 #,(cadddr form))))))
> 
> Andre

Thanks. I can get this to work using:

(ex:repl '((import (rnrs)) ...


but is there some way to get an *interactive* repl in one of the 
compatible schemes? I've tried the existing 
r6rs-expander-vantonder.plt, but it's kind annoying to use. For 
example, if I enter your definition above:

R5.97RS> (define-syntax if-it
     (lambda (form)
       (let ((it (datum->syntax (car form) 'it)))
         #`(let ((#,it #,(cadr form)))
            (if #,it
                #,(caddr form)
                #,(cadddr form))))))

Syntax violation: invalid reference

Attempt to use binding of lambda in library () at invalid level 1.  
Binding is only available at levels: 0

Form: lambda

Trace: 

  (lambda (form)
  (let ((it (datum->syntax (car form) 'it)))
    (quasisyntax
      (let (((unsyntax it) (unsyntax (cadr form))))
        (if (unsyntax it) (unsyntax (caddr form)) (unsyntax (cadddr form)))))))

syntax-violation: Integrate with host error handling here

More or less defeats the purpose of a repl if I have to define a 
library for such simple things - unless I'm misunderstanding the error 
altogether.
From: William D Clinger
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <5c7a0076-f785-4011-8416-f40c525fde2a@e25g2000prg.googlegroups.com>
Raffael Cavallaro wrote:
> Thanks. I can get this to work using:
>
> (ex:repl '((import (rnrs)) ...
>
> but is there some way to get an *interactive* repl in one of the
> compatible schemes?

Larceny's ERR5RS mode uses Andre's interactive REPL as
its native REPL:

% larceny -err5rs
Larceny v0.961 "Fluoridation" (Jan  2 2008 04:27:56,
precise:SunOS5:split)
ERR5RS mode (no libraries have been imported)

> (import (rnrs))
Autoloading (rnrs)
Autoloading (rnrs enums)
Autoloading (rnrs lists)
Autoloading (rnrs syntax-case)
Autoloading (rnrs hashtables)
Autoloading (rnrs arithmetic bitwise)
Autoloading (rnrs programs)
Autoloading (rnrs files)
Autoloading (rnrs io ports)
Autoloading (larceny deprecated)
Autoloading (rnrs conditions)
Autoloading (rnrs exceptions)
Autoloading (rnrs records syntactic)
Autoloading (err5rs records procedural)
Autoloading (rnrs records procedural)
Autoloading (rnrs control)
Autoloading (rnrs sorting)
Autoloading (rnrs bytevectors)
Autoloading (rnrs unicode)

> (define-syntax if-it
     (lambda (form)
       (let ((it (datum->syntax (car form) 'it)))
         #`(let ((#,it #,(cadr form)))
            (if #,it
                #,(caddr form)
                #,(cadddr form))))))

>

Will
From: Raffael Cavallaro
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <2008021401520275249-raffaelcavallaro@pasdespamsilvousplaitmaccom>
On 2008-02-13 22:12:38 -0500, William D Clinger <········@yahoo.com> said:

> Larceny's ERR5RS mode uses Andre's interactive REPL as
> its native REPL:
> 
> % larceny -err5rs
> Larceny v0.961 "Fluoridation" (Jan  2 2008 04:27:56,
> precise:SunOS5:split)
> ERR5RS mode (no libraries have been imported)
> 
>> (import (rnrs))

Ah, I remember now reading something about this on the larceny mailing 
list. Thanks - I've just written, compiled, loaded, imported and run my 
first err5rs/r6rs library - works nicely.
From: llama
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <aL6dnYXCnN2ITC7anZ2dnUVZ8vGdnZ2d@saix.net>
"William D Clinger" <········@yahoo.com> wrote in message 
·········································@e25g2000prg.googlegroups.com...
> Raffael Cavallaro wrote:
>> Thanks. I can get this to work using:
>>
>> (ex:repl '((import (rnrs)) ...
>>
>> but is there some way to get an *interactive* repl in one of the
>> compatible schemes?
>
> Larceny's ERR5RS mode uses Andre's interactive REPL as
> its native REPL:
>
> % larceny -err5rs
> Larceny v0.961 "Fluoridation" (Jan  2 2008 04:27:56,
> precise:SunOS5:split)
> ERR5RS mode (no libraries have been imported)
>
>> (import (rnrs))
> Autoloading (rnrs)
> Autoloading (rnrs enums)
> Autoloading (rnrs lists)
> Autoloading (rnrs syntax-case)
> Autoloading (rnrs hashtables)
> Autoloading (rnrs arithmetic bitwise)
> Autoloading (rnrs programs)
> Autoloading (rnrs files)
> Autoloading (rnrs io ports)
> Autoloading (larceny deprecated)
> Autoloading (rnrs conditions)
> Autoloading (rnrs exceptions)
> Autoloading (rnrs records syntactic)
> Autoloading (err5rs records procedural)
> Autoloading (rnrs records procedural)
> Autoloading (rnrs control)
> Autoloading (rnrs sorting)
> Autoloading (rnrs bytevectors)
> Autoloading (rnrs unicode)
>
>> (define-syntax if-it
>     (lambda (form)
>       (let ((it (datum->syntax (car form) 'it)))
>         #`(let ((#,it #,(cadr form)))
>            (if #,it
>                #,(caddr form)
>                #,(cadddr form))))))
>
>>
>
> Will


That's nice. Now show an usage example. Every Scheme I tried choked on on 
the application of that macro. 
From: William D Clinger
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <926fd1e5-5d72-4ed9-91d0-13102c5a560a@s8g2000prg.googlegroups.com>
llama wrote:
> That's nice. Now show an usage example. Every Scheme I tried choked on on
> the application of that macro.

It works in Larceny.  See below.

Will

--------

% larceny -err5rs
Larceny v0.961 "Fluoridation" (Jan 19 2008 12:07:22,
precise:SunOS5:split)
ERR5RS mode (no libraries have been imported)

> (import (rnrs))
Autoloading (rnrs)
Autoloading (rnrs enums)
Autoloading (rnrs lists)
Autoloading (rnrs syntax-case)
Autoloading (rnrs hashtables)
Autoloading (rnrs arithmetic bitwise)
Autoloading (rnrs programs)
Autoloading (rnrs files)
Autoloading (rnrs io ports)
Autoloading (larceny deprecated)
Autoloading (rnrs conditions)
Autoloading (rnrs exceptions)
Autoloading (rnrs records syntactic)
Autoloading (err5rs records procedural)
Autoloading (rnrs records procedural)
Autoloading (rnrs control)
Autoloading (rnrs sorting)
Autoloading (rnrs bytevectors)
Autoloading (rnrs unicode)

> (define-syntax if-it
     (lambda (form)
       (let ((it (datum->syntax (car form) 'it)))
         #`(let ((#,it #,(cadr form)))
            (if #,it
                #,(caddr form)
                #,(cadddr form))))))

> (if-it #t 'then 'else)
then

> (if-it #f 'then 'else)
else

> (if-it #t it 'else)
#t

> ;; Now for a more familiar use of intentional capture.
  (define-syntax myloop
    (lambda (form)
      (let ((break (datum->syntax (car form) 'break)))
        #`(call/cc
           (lambda (k)
             (let ((#,break k))
               (do ()
                   (#f)
                   (begin #,@(cdr form)))))))))

> (let ((x '(3 2 1 0 -1 -2 -3 -4)))
    (myloop (if (zero? (car x))
                (break (cdr x))
                (set! x (cdr x)))))
(-1 -2 -3 -4)
From: Abdulaziz Ghuloum
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fp0m97$iki$1@aioe.org>
llama wrote:

> Now show an usage example. Every Scheme I tried choked on 
> on the application of that macro.

Andre already told you that this macro that he's written uses
an extension that's not supported by any any implementation
except larceny (by virtue of using his system).  Fortunate or
unfortunate, there *is* a portable way (as far as R6RS goes)
of writing this macro as shown below (it might run on other
systems that I have not tested).  The portable version also
happens to be more robust--it gives a better error message if
the input is malformed instead of giving the ``error in
caddr'' sort of error that you'd get otherwise.

Pick the version that better suits your needs.

Aziz,,,



$ ikarus
Ikarus Scheme version 0.0.3+ (revision 1384, build 2008-02-13)
Copyright (c) 2006-2008 Abdulaziz Ghuloum

 > (define-syntax if-it
     (lambda (stx)
       (syntax-case stx ()
         ((ctxt test conseq altern)
          (let ((it (datum->syntax #'ctxt 'it)))
            #`(let ((#,it test))
                (if #,it conseq altern)))))))
 > (if-it 17 it 18)
17


$ larceny -err5rs
Larceny v0.961 "Fluoridation" (Jan  2 2008 04:30:22, precise:Posix 
Unix:unified)
larceny.heap, built on Wed Jan  2 04:41:29 EST 2008
ERR5RS mode (no libraries have been imported)

 > (import (rnrs))
Autoloading ...

 > (define-syntax if-it
     (lambda (stx)
       (syntax-case stx ()
         ((ctxt test conseq altern)
          (let ((it (datum->syntax #'ctxt 'it)))
            #`(let ((#,it test))
                (if #,it conseq altern)))))))

 > (if-it 17 it 18)
17


$ mzscheme
Welcome to MzScheme v3.99.0.10 [3m], Copyright (c) 2004-2008 PLT Scheme Inc.
 > (define-syntax if-it
     (lambda (stx)
       (syntax-case stx ()
         ((ctxt test conseq altern)
          (let ((it (datum->syntax #'ctxt 'it)))
            #`(let ((#,it test))
                (if #,it conseq altern)))))))
 > (if-it 17 it 18)
17


$ petite
Petite Chez Scheme Version 7.4
Copyright (c) 1985-2007 Cadence Research Systems

 > (define-syntax if-it
     (lambda (stx)
       (syntax-case stx ()
         ((ctxt test conseq altern)
          (let ((it (datum->syntax #'ctxt 'it)))
            #`(let ((#,it test))
                (if #,it conseq altern)))))))
 > (if-it 17 it 18)
17
From: llama
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <bvmdnVBDOfVI_inanZ2dnUVZ8uWdnZ2d@saix.net>
"Abdulaziz Ghuloum" <········@cee.ess.indiana.edu> wrote in message 
·················@aioe.org...
> llama wrote:
>
>> Now show an usage example. Every Scheme I tried choked on on the 
>> application of that macro.
>
> Andre already told you that this macro that he's written uses
> an extension that's not supported by any any implementation
> except larceny (by virtue of using his system).

Thanks, I must have missed that part. 
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <61h2e8F1v5g13U1@mid.individual.net>
············@yahoo.com wrote:
> On Feb 12, 12:31 pm, Raffael Cavallaro <················@pas-d'espam-
> s'il-vous-plait-mac.com> wrote:
> 
>> Not that I doubt the power of your system Andre, but could you show us
>> a simple example of intentional capture inside a #` form?
> 
>   (define-syntax if-it
>     (lambda (form)
>       (let ((it (datum->syntax (car form) 'it)))
>         #`(let ((,it ,(cadr form)))
>            (if #,it
>                #,(caddr form)
>                #,(cadddr form))))))
> 
> DATUM->SYNTAX overrides hygiene by creating the identifier IT as if 
> it appeared in the source at the position of (CAR FORM), i.e., the
> IF-IT at the usage site of the macro.  You may think of this, very
> roughly, as a standard way of making an identifier that is not
> affected by the automatic gensym that would otherwise be applied by
> #`.

This sounds like I have to say twice where the identifier is inserted. 
That's weird. Why is that the case?

> This is slightly longer than the defmacro way, but macros that 
> capture are usually a minority.

Says who?

> Some unfortunately do not represent code as s-expressions and rely on
> pattern matching to decompose their input. While there are reasons
> for their design choice, I think it very unfortunately obscures the
> fact that pattern matching is absolutely orthogonal to - and
> unnecessary for - the hygiene mechanism. As a result, people like the
> OP get the impression that hygiene is more complicated than it really
> is, and cannot entirely be blamed for giving up in disgust.

Yes, you're macro system looks more attractive than syntax-case to me. I 
understand that syntax-rules can be neat when it's all you need, but for 
more complex stuff, s-expressions are simply better (IMHO, and at all 
that, of course).

Does your system also support the kinds of macros that are mentioned for 
example in 
http://www.lispworks.com/documentation/HyperSpec/Issues/iss066_w.htm ?


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: ·················@gmail.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <7190c87e-4bdd-4719-b6c6-4ef12efa25df@y5g2000hsf.googlegroups.com>
I have been skeptical about Scheme macros for a long time,
thinking that syntax-rules is too simple and syntax-case too complex,
and I have been using define-macro instead. However, in the last
couple of months I have somewhat changed my mind. I figured out that
the biggest issue I had with syntax-case was notational. If you are
willing to dress it with a minor amount of sugar, syntax-case becomes
pretty easy to use and quite readable too. Here is the swap! example:

(define-syntax-case swap! ()
  ((swap! x y) (let ((t x)) (set! x y) (set! y t))))

define-syntax-case is just sugar around syntax-case:

;; tested on Ikarus Scheme
(define-syntax define-syntax-case
  (syntax-rules ()
    ((_ name (literal ...)
        ((_ arg ...) templ) ...)
     (define-syntax name
       (lambda (x)
         (syntax-case x (<expand> literal ...)
           ((ctx <expand> arg ...) #`'templ) ...
           ((ctx arg ...) #`templ) ...))))
    ((_ name (literal ...)
        ((_ arg ...) fender templ) ...)
     (define-syntax name
       (lambda (x)
         (syntax-case x (<expand> literal ...)
           ((ctx <expand> arg ...) fender #`'templ) ...
           ((ctx arg ...) fender #`templ) ...))))
    ))

Notice that I also added an <expand> feature to see the expansion
of the macro:

(swap! <expand> x y) ;=> (let ((t x)) (set! x y) (set! y t))


Michele Simionato
From: Abdulaziz Ghuloum
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fosvad$r1h$1@aioe.org>
·················@gmail.com wrote:

> (define-syntax define-syntax-case
>   (syntax-rules ()
>     ((_ name (literal ...)
>         ((_ arg ...) templ) ...)
>      (define-syntax name
>        (lambda (x)
>          (syntax-case x (<expand> literal ...)
>            ((ctx <expand> arg ...) #`'templ) ...
>            ((ctx arg ...) #`templ) ...))))
>     ((_ name (literal ...)
>         ((_ arg ...) fender templ) ...)
>      (define-syntax name
>        (lambda (x)
>          (syntax-case x (<expand> literal ...)
>            ((ctx <expand> arg ...) fender #`'templ) ...
>            ((ctx arg ...) fender #`templ) ...))))
>     ))

I wonder how this would look using s-expression manipulation
(cars/cdrs).  Andre, since you seem to be the expert on this,
do you want to give it a shot?
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <bfccfd72-55d8-4470-8273-a4998a845aef@e10g2000prf.googlegroups.com>
On Feb 12, 3:24 pm, Abdulaziz Ghuloum <········@cee.ess.indiana.edu>
wrote:
> ·················@gmail.com wrote:
> > (define-syntax define-syntax-case
> >   (syntax-rules ()
> >     ((_ name (literal ...)
> >         ((_ arg ...) templ) ...)
> >      (define-syntax name
> >        (lambda (x)
> >          (syntax-case x (<expand> literal ...)
> >            ((ctx <expand> arg ...) #`'templ) ...
> >            ((ctx arg ...) #`templ) ...))))
> >     ((_ name (literal ...)
> >         ((_ arg ...) fender templ) ...)
> >      (define-syntax name
> >        (lambda (x)
> >          (syntax-case x (<expand> literal ...)
> >            ((ctx <expand> arg ...) fender #`'templ) ...
> >            ((ctx arg ...) fender #`templ) ...))))
> >     ))
>
> I wonder how this would look using s-expression manipulation
> (cars/cdrs).  Andre, since you seem to be the expert on this,
> do you want to give it a shot?

I'll leave that to the Lispniks, who have more practice
with this kind of thing.  It might even occur to some of
them that pattern matching, despite being orthogonal to and
unnecessary for hygiene, is a quite useful thing to have.
From: ·················@gmail.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <90a7671d-c295-4d19-b525-c5463ebc57cf@d21g2000prf.googlegroups.com>
On Feb 13, 12:03 am, ············@yahoo.com wrote:

> I'll leave that to the Lispniks, who have more practice
> with this kind of thing.  It might even occur to some of
> them that pattern matching, despite being orthogonal to and
> unnecessary for hygiene, is a quite useful thing to have.

Actually one of the reasons why I changed my mind about Scheme
macros is that I realized the benefits of pattern matching
when writing complex macros. BTW, I just noticed that I have posted
the wrong version of define-syntax-case, the correct one is

(define-syntax define-syntax-case
  (syntax-rules ()
    ((_ name (literal ...)
        ((ctx arg ...) templ) ...)
     (define-syntax name
       (lambda (x)
         (syntax-case x (<expand> literal ...)
           ((ctx <expand> arg ...) #`'templ) ...
           ((ctx arg ...) #`templ) ...))))
    ((_ name (literal ...)
        ((ctx arg ...) fender templ) ...)
     (define-syntax name
       (lambda (x)
         (syntax-case x (<expand> literal ...)
           ((ctx <expand> arg ...) fender #`'templ) ...
           ((ctx arg ...) fender #`templ) ...))))
    ))
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <61ddqvF1ug7s4U1@mid.individual.net>
Ken Tilton wrote:
> While trying to explain my irrational prejudice against Scheme macros I 
> got curious as to why I hated them, so I googled up this:
> 
>   http://www.xs4all.nl/~hipster/lib/scheme/gauche/define-syntax-primer.txt
> 
> Boys and girls, that is almost eleven thousand words long!!!!!
> 
> I see the problem, they have this whole pattern-matching syntax-rules 
> language moving from source input to output. I have done (and am 
> supposed to be doing) enough Prolog to realize Scheme macro writers must 
> be way smarter than me. But... why? No, not why are they smarter. Why do 
> they have to be smarter? What was wrong with treating the source as an 
> ordinary tree of data and just whinging it about with Scheme itself to 
> produce the output? Please restrict yourself to one or more of these 
> answers:
> 
> 1. The hygiene made us do it.

No, there are hygienic macro systems where source is a tree of data. 
Actually, in most hygienic macro systems, source is still a tree of data.

> 2. We actually thought it would be way cool and super powerful.

Lisp-style macros (as in Common Lisp) provide backquote as a convenient 
means to construct new s-expressions. One nice thing about backquote is 
that you can make backquote expressions look very close the code you 
have in your mind. (Compare `(progn ,@body) to (cons 'progn body), for 
example.)

Common Lisp also provides destructuring macro lambda lists, where you 
can already preprocess the arguments a macro receives by tearing them 
apart into subparts. For example: (defmacro with ((&rest bindings) &body 
body) ...) instead of (defmacro with (&rest code) ...).

Backquote works pretty well. However, destructuring macro lambda lists 
are limited - note how to you can't see the constituents of the bindings 
list in the with example. You have to 'manually' tear them apart. (Loop 
is pretty good at such things, but you still have to do it.)

If you want to make destructuring more fine-grained, you also have to 
make changes to the corresponding construct for reconstructing code 
(like backquote). That's where the complexity comes in.

Syntax-rules and syntax-case work quite well in that regard (although I 
personally prefer to use LOOP).

> 3. We were embarrassd by the small size of the standard and decided to 
> make it up in the macro language

They could have kept the spec smaller by sticking to Lisp-style macros 
and adding a rename construct. The other macro systems can be built on 
top of that. I guess removing the weaknesses and restrictions that make 
additional features appear necessary is not so important after all. :-P

To be more serious: Syntax-rules is a macro system that is very simple 
to use for very simple macros. You sometimes want to define your own 
macros to illustrate some points in academic papers. Syntax-rules macros 
are more than good enough for such purposes, and the macro definitions 
can be read by people who are not used to macro programming. That's a 
good thing, if the macro is not the main part of what you want to 
discuss. Macro definitions in such papers hardly need to be complex (and 
can always be simplified for illustration purposes).

You know, there is more you can do with programming languages than 
writing applications...


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Jens Axel Soegaard
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <47b19d5c$0$2094$edfadb0f@dtext02.news.tele.dk>
Ken Tilton wrote:
> While trying to explain my irrational prejudice against Scheme macros I 
> got curious as to why I hated them, so I googled up this:
> 
>   http://www.xs4all.nl/~hipster/lib/scheme/gauche/define-syntax-primer.txt
> 
> Boys and girls, that is almost eleven thousand words long!!!!!

And "On Lisp" is even longer!!!!!

"Primer" is obviously not to be taken literally.

> I see the problem, they have this whole pattern-matching syntax-rules 
> language moving from source input to output. I have done (and am 
> supposed to be doing) enough Prolog to realize Scheme macro writers must 
> be way smarter than me. But... why? No, not why are they smarter. Why do 
> they have to be smarter? What was wrong with treating the source as an 
> ordinary tree of data and just whinging it about with Scheme itself to 
> produce the output? 

The use of pattern matching is a detail.

That's not why Schemers abandoned the old way. There are *two* goals of 
modern Scheme macro systems. Hygiene (i.e. automatic renaming) as 
another Paris Hilton got all the press, while the referentially 
transparent property was left behind in the dust.

Referentially transparent macros?

   If a macro transformer inserts a free reference to an identifier,
   the reference refers to the binding that was visible where the
   transformer was specified, regardless of any local bindings that may
   surround the use of the macro.

In short the meaning of the expansion of a macro doesn't depend on where 
it is used. In order to implement that you need to attach information
to variables, and thus symbols are replaced by "syntax-objects
representing symbols".


For a CL view on the matters see these posts in a very informative
thread on Scheme macros in comp.lang.lisp in 2004.

Anton van Straaten in comp.lang.lisp:
http://groups.google.com/group/comp.lang.lisp/msg/4cfdf326287b3d01

Pascal Constanza in comp.lang.lisp:
http://groups.google.com/group/comp.lang.lisp/msg/67d80b9d8da8c085



Anyhow, stop reading about syntax-rules (so last millenium) and treat 
yourself with some light reading on syntax-case. Dybvig's

  Writing Hygenic Macros in Scheme with Syntax-Case
  ftp://ftp.cs.indiana.edu/pub/scheme-repository/doc/pubs/iucstr356.ps.gz

is a must read.

So is Dybvig's contribution to the book "Beautiful code":
    http://www.cs.indiana.edu/~dyb/pubs/bc-syntax-case.pdf


-- 
Jens Axel S�gaard
From: Kjetil S. Matheussen
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <Pine.LNX.4.58.0802121427320.3440@notam02.uio.no>
On Tue, 12 Feb 2008, Jens Axel Soegaard wrote:

> Ken Tilton wrote:
> > While trying to explain my irrational prejudice against Scheme macros I 
> > got curious as to why I hated them, so I googled up this:
> > 
> >   http://www.xs4all.nl/~hipster/lib/scheme/gauche/define-syntax-primer.txt
> > 
> > Boys and girls, that is almost eleven thousand words long!!!!!
> 
> And "On Lisp" is even longer!!!!!
> 
> "Primer" is obviously not to be taken literally.
> 
> > I see the problem, they have this whole pattern-matching syntax-rules 
> > language moving from source input to output. I have done (and am 
> > supposed to be doing) enough Prolog to realize Scheme macro writers must 
> > be way smarter than me. But... why? No, not why are they smarter. Why do 
> > they have to be smarter? What was wrong with treating the source as an 
> > ordinary tree of data and just whinging it about with Scheme itself to 
> > produce the output? 
> 
> The use of pattern matching is a detail.
> 
> That's not why Schemers abandoned the old way.

I wouldn't say that. My impression is that most scheme implementations,
and all the large ones (anyone who doesn't?), support define-macro. I 
would actually also be surprised if hygenic macros is more used by 
schemeres than "the old way", although I don't have any data to back
that up with. Anyway, I would never use a scheme where you couldn't
write macros the old way.
From: Eli Barzilay
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <m3ir0tgazp.fsf@winooski.ccs.neu.edu>
"Kjetil S. Matheussen" <··············@notam02.no> writes:

> I wouldn't say that. My impression is that most scheme
> implementations, and all the large ones (anyone who doesn't?),
> support define-macro. I would actually also be surprised if hygenic
> macros is more used by schemeres than "the old way", although I
> don't have any data to back that up with. [...]

Out of curiosity, I inspected the PLT collects tree.  Here's a
summary:

* about 400K lines of Scheme code

* 12 occurrences of `define-macro'; 5 are in the define-macro library
  source, 3 in comments, 4 are in misc meta-code (keyword colors,
  indentation, etc), that leaves 0 uses in real code.

* 1438 occurrences of `define-syntax' (and `...-syntaxes')

* 1360 of `syntax-case'

* 468 of `syntax-rules'

It's interesting to compare this to version 103 (which is before PLT
switched to `syntax-case' being native):

* About 150K lines

* 125 `define-macro'

* 7 `define-syntax', 1 `syntax-rules', 1 `syntax-case' none is
  actually used

And here's an interesting result: if the switch to the new system
would mean changing all `define-macro's to `define-syntax', and
assuming the same "macro use density" per line of code, then you'd
expect to see about 300 syntax definitions.  So the new macro system is
robust enough that it is used about 4.5 times more often than
define-macro.

-- 
          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                  http://www.barzilay.org/                 Maze is Life!
From: Abdulaziz Ghuloum
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fot4lg$eq1$1@aioe.org>
Eli Barzilay wrote:

> So the new macro system is robust enough that it  is
> used  about 4.5 times more often than define-macro.

Or, it may be that you guys are just macro noobs.  You
can't handle the power of lisp macros, and you want
this thing called "hygiene" to protect you from the so
called "unintended capture" straw-man that you throw
around at every occasion.

The real programmer does not need no stinkin' hygiene.
From: Eli Barzilay
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <m3ejbh9bn1.fsf@winooski.ccs.neu.edu>
Abdulaziz Ghuloum <········@cee.ess.indiana.edu> writes:

> Eli Barzilay wrote:
>
>> So the new macro system is robust enough that it  is
>> used  about 4.5 times more often than define-macro.
>
> Or, it may be that you guys are just macro noobs.

No.


> You can't handle the power of lisp macros, and you want this thing
> called "hygiene" to protect you from the so called "unintended
> capture" straw-man that you throw around at every occasion.
>
> The real programmer does not need no stinkin' hygiene.

-- 
          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                  http://www.barzilay.org/                 Maze is Life!
From: ········@yoho-gmail.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <9bf67944-9feb-4bba-8b97-b4a098de9923@1g2000hsl.googlegroups.com>
On Feb 12, 9:45 pm, Eli Barzilay <····@barzilay.org> wrote:
> "Kjetil S. Matheussen" <··············@notam02.no> writes:
>
> > I wouldn't say that. My impression is that most scheme
> > implementations, and all the large ones (anyone who doesn't?),
> > support define-macro. I would actually also be surprised if hygenic
> > macros is more used by schemeres than "the old way", although I
> > don't have any data to back that up with. [...]
>
> Out of curiosity, I inspected the PLT collects tree.  Here's a
> summary:
>
> * about 400K lines of Scheme code
>
> * 12 occurrences of `define-macro'; 5 are in the define-macro library
>   source, 3 in comments, 4 are in misc meta-code (keyword colors,
>   indentation, etc), that leaves 0 uses in real code.
>
> * 1438 occurrences of `define-syntax' (and `...-syntaxes')
>
> * 1360 of `syntax-case'
>
> * 468 of `syntax-rules'
>

As a comparison, here a grep through the chicken code repository
(including tagged versions):

define-macro: 9235
define-syntax: 5504
syntax-rules: 5249


cheers,
felix
From: William D Clinger
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <d7715640-b66f-46ed-88c2-7562886ad201@e6g2000prf.googlegroups.com>
Tabulating data collected by Eli Barzilay and
Felix Winkelmann:

                      PLT   Chicken    Larceny
define-macro           12      9235         67
define-syntax        1438      5504       1806
syntax-rules          468      5249       1703
syntax-case          1360         ?        271

For Larceny, most of the macros are defined in
libraries and benchmarks written by people who
are not themselves developers of Larceny.

Will
From: William D Clinger
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <1a52845e-f3dd-449d-a597-ed833dc6b433@b74g2000hsg.googlegroups.com>
Felix Winkelmann wrote:
> As a comparison, here a grep through the chicken code repository
> (including tagged versions):

If a macro is present in many tagged versions, then it
gets counted once for every version.  That bothered me,
so I decided to do the grep myself for all three systems.
I did a wget from

http://pre.plt-scheme.org/plt-clean-tree.tgz

and an svn export from

https://galinha.ucpel.tche.br/svn/chicken-eggs/
http://larceny.ccs.neu.edu/svn/trunk/larceny_src

From chicken-eggs, I then deleted all directories named
"tags" or "branches".  This left:

           all files         Scheme files
                          -------------------
                          MB      #      KLOC
PLT          85 MB        24    2655      627
Chicken     185 MB        53    5008     1470
Larceny      47 MB        12    1193      344

I then grepped the remaining .sch, .scm, and .ss files
for "define-macro", "define-syntax", "syntax-rules",
and "syntax-case".  Results:

                      PLT   Chicken    Larceny
define-macro           66      4234         67
define-syntax        1908      3583       1807
syntax-rules          651      3297       1704
syntax-case          1675      1110        272

Each of the three columns shows a different pattern, so
generalizations based on a single programmer's experience
or on the code written for any one implementation should
be regarded with skepticism.

Will
From: Alex Shinn
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <84dfdc8d-1c28-460d-a12e-51fef0d35b69@d4g2000prg.googlegroups.com>
On Feb 15, 6:40 am, William D Clinger <········@yahoo.com> wrote:
>
>                       PLT   Chicken    Larceny
> define-macro           66      4234         67
> define-syntax        1908      3583       1807
> syntax-rules          651      3297       1704
> syntax-case          1675      1110        272

  sc-macro-transformer             16

Though in all fairness 7 of those were from the
syntactic-closures egg itself.

Chicken has no active uses of er-macro-transformer.

--
Alex
From: Raffael Cavallaro
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <2008021501545850878-raffaelcavallaro@pasdespamsilvousplaitmaccom>
On 2008-02-14 16:40:06 -0500, William D Clinger <········@yahoo.com> said:

> Results:
> 
>                       PLT   Chicken    Larceny
> define-macro           66      4234         67
> define-syntax        1908      3583       1807
> syntax-rules          651      3297       1704
> syntax-case          1675      1110        272
> 
> Each of the three columns shows a different pattern, so
> generalizations based on a single programmer's experience
> or on the code written for any one implementation should
> be regarded with skepticism.

I wonder what the column for Gambit would look like - syntax-case and 
define-syntax are not loaded by default in Gambit so I would suspect 
they don't figure heavily in Gambit's own source.
From: Joel J. Adamson
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <87myq2kzxc.fsf@W0053328.mgh.harvard.edu>
Raffael Cavallaro <················@pas-d'espam-s'il-vous-plait-mac.com>
writes:

> On 2008-02-14 16:40:06 -0500, William D Clinger <········@yahoo.com> said:
>
>> Results:
>>
>>                       PLT   Chicken    Larceny
>> define-macro           66      4234         67
>> define-syntax        1908      3583       1807
>> syntax-rules          651      3297       1704
>> syntax-case          1675      1110        272
>>
>> Each of the three columns shows a different pattern, so
>> generalizations based on a single programmer's experience
>> or on the code written for any one implementation should
>> be regarded with skepticism.
>
> I wonder what the column for Gambit would look like - syntax-case and
> define-syntax are not loaded by default in Gambit so I would suspect
> they don't figure heavily in Gambit's own source.

We were simultaneously having a similar discussion on gambit-list: A
quick check of the examples turned up (obviously) no uses of syntax-case
style macros.  This discussion started with my mistaken presumption that
I needed to use syntax-case macros and dealing with the problems created
by loading the syntax-case library packaged with Gambit.  The response
from a few readers was that Gambit favors define-macro, and indeed
that's all that I find in the examples and I, personally find their
construction more intuitive than syntax-rules templates.

Joel

-- 
Joel J. Adamson
Biostatistician
Pediatric Psychopharmacology Research Unit
Massachusetts General Hospital
Boston, MA  02114
(617) 643-1432
(303) 880-3109
From: Jens Axel Soegaard
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <47b1c55b$0$2110$edfadb0f@dtext02.news.tele.dk>
Kjetil S. Matheussen wrote:

>> That's not why Schemers abandoned the old way.
> 
> I wouldn't say that. My impression is that most scheme implementations,
> and all the large ones (anyone who doesn't?), support define-macro. I 
> would actually also be surprised if hygenic macros is more used by 
> schemeres than "the old way", although I don't have any data to back
> that up with. Anyway, I would never use a scheme where you couldn't
> write macros the old way.

Nowadays there are (depending on point of view) two different
types of define-macro forms. One type is define-macro implemented
on top of define-syntax - this type is generally found in
implementations that have "full" syntax-case integration.

The other one is found in implementations where syntax-case
is treated as an "add on" builds on a "native" define-macro.

The two types are for simple macros equivalent, but for macros
that require phase 2 [*] computations hell is likely to break
loose.

There are two things I look for, when I evaluate macro systems:

  1) How easy is it to give error messages in terms of the
     *original* user syntax?

  2) Can the module system handle the macro system?
     [I.e. how (if at all) is the phase problem solved?]

Most "native" define-macro systems handle these points on an
ad hoc basis.


[*]
http://pre.plt-scheme.org/docs/html/reference/Evaluation_Model.html#(part~20module-phase)
From: Eli Barzilay
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <m3ejbhgarp.fsf@winooski.ccs.neu.edu>
Ken Tilton <···········@optonline.net> writes:

> While trying to explain my irrational prejudice against Scheme
> macros I got curious as to why I hated them, so I googled up this:
>
>   http://www.xs4all.nl/~hipster/lib/scheme/gauche/define-syntax-primer.txt
>
> Boys and girls, that is almost eleven thousand words long!!!!!

Note the name of the document -- it describes `syntax-rules' and how
to do with it things that seem impossible from a very restricted
syntax rewriting system.  Using *just* that is on the same masochistic
level as using *just* r5rs for real programming.

-- 
          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                  http://www.barzilay.org/                 Maze is Life!
From: Maciej Katafiasz
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <foslv5$n45$1@news.net.uni-c.dk>
Den Tue, 12 Feb 2008 04:46:15 -0500 skrev Ken Tilton:

> While trying to explain my irrational prejudice against Scheme macros I
> got curious as to why I hated them, so I googled up this:
> 
>    http://www.xs4all.nl/~hipster/lib/scheme/gauche/define-syntax-
primer.txt
> 
> Boys and girls, that is almost eleven thousand words long!!!!!

Woah there, back in my day, a three-article technical *series* was 
absolutely, unquestionably, your editor is really good at using Delete 
thank you very much limited to 6K words (including intros, conclusions 
and recaps). So that's two complete series there.

> Please restrict yourself to one or more of these
> answers:
> 
> 4. Other _____________________

They had to write articles with strict wordcount limits before and decide 
that this time fuck it, *they* will decide when to stop.

Cheers,
Maciej
From: Alex Shinn
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <8643e597-ac50-45eb-90bd-adf66f84b26a@m34g2000hsb.googlegroups.com>
>>>>> "Ken" == Ken Tilton <···········@optonline.net> writes:

    [ ... why syntax-rules? ... ]

    Ken> 4. Other _____________________

I won't presume as to the R5RS editors original reasons, but
I suspect it has to do with the fact that SYNTAX-RULES was
and remains the simplest and most natural macro system for
describing all of the derived syntax in R5RS itself.

There are plenty of other cases where SYNTAX-RULES clearly
wins.  Just consider the confusion that a newbie recently
ran into trying to use DEFINE-MACRO:

  http://list.cs.brown.edu/pipermail/plt-scheme/2008-February/022777.html

... and how SYNTAX-RULES saves the day:

  http://list.cs.brown.edu/pipermail/plt-scheme/2008-February/022782.html

--
Alex
From: Kaz Kylheku
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <45ec293d-e46f-4bbf-93cb-cbd83b96ce6c@e23g2000prf.googlegroups.com>
On Feb 13, 5:39 am, Alex Shinn <·········@gmail.com> wrote:
> There are plenty of other cases where SYNTAX-RULES clearly
> wins.  Just consider the confusion that a newbie recently
> ran into trying to use DEFINE-MACRO:
>
>  http://list.cs.brown.edu/pipermail/plt-scheme/2008-February/022777.html
>
> ... and how SYNTAX-RULES saves the day:
>
>  http://list.cs.brown.edu/pipermail/plt-scheme/2008-February/022782.html

I can hardly make heads or tails out of the nested defspel. I need to
see the nested backquotes to see what is the meta-level and what is
meta-meta, otherwise my eyes glaze over. I can't see what part of the
template is literal, and what part is spliced in, because nothing is
denoting that. And look, even though things are quoted, they are still
substituted. You have expressions like (eq? 'object 'obj), but this is
really like `(eq? (quote ,object) (quote ,obj)). It looks like these
are simple quoted literal symbols, but no, there is still evaluation
taking place. Confusing! Suppose you're a sloppy Frenchman and make a
typo and write (eq? 'objet 'obj). The 'objet is now literal, because
objet isn't a macro parameter. That's evil!

This basically brings us back to the stone age of C language macros:

  #define STR(X) #X
  #define SPEL(OBJECT, SUBJECT) foo(SUBJECT, STR(OBJET))

Look at this, here, too, there is no ugly backquote to confuse
newbies! C preprocessor saves the day! Of course, when you call
SPEL(X, Y) you end up with foo(X, "OBJET") instead of foo(X, "Y").
Oops!
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <c1f34d0e-a312-46e7-a0cc-af056de5c881@u10g2000prn.googlegroups.com>
On Feb 13, 3:47 pm, Kaz Kylheku <········@gmail.com> wrote:

> I can hardly make heads or tails out of the nested defspel. I need to
> see the nested backquotes to see what is the meta-level and what is
> meta-meta, otherwise my eyes glaze over.

This may be a question of familiarity.  I tend to glaze
over when confronted by the nested quasiquotations that tend to
appear
in macro-generating macros.  Here is a snippet from
one of my own old define-macros

       `(define-macro (,name ,k ,@args)
         `(,,k ,',supers ,',labels ,@,args)))))

and a little quiz:

  (let ((x '(a b c))) ``(,,x ,@,x ,,@x ,@,@x))   => ??

Define-syntax templates are easier for me in these situations.

> I can't see what part of the
> template is literal, and what part is spliced in, because nothing is
> denoting that.

That is certainly a valid complaint.  It could be mitigated somewhat
by
a notational convention like

 (define-syntax swap
   (syntax-rules ()
     ((_ x y) (LET ((TEMP x))
                (SET! x y)
                (SET! y TEMP)))))

or by text colorization in a sufficiently smart editor.  But this is
not typically something that seems to trip up Scheme macro writers
too much.
From: Kaz Kylheku
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <c06c9f40-b700-4348-87fe-b628a87ef590@s37g2000prg.googlegroups.com>
On Feb 15, 7:18 am, ············@yahoo.com wrote:
> On Feb 13, 3:47 pm, Kaz Kylheku <········@gmail.com> wrote:
>
> > I can hardly make heads or tails out of the nested defspel. I need to
> > see the nested backquotes to see what is the meta-level and what is
> > meta-meta, otherwise my eyes glaze over.
>
> This may be a question of familiarity. I tend to glaze
> over when confronted by the nested quasiquotations that tend to
> appear in macro-generating macros.
>
> Here is a snippet from
> one of my own old define-macros
>
>        `(define-macro (,name ,k ,@args)
>          `(,,k ,',supers ,',labels ,@,args)))))

Even in the absence of enough context, I know what's going on here. I
don't have the bindings of name, k, supers and labels are, but I can
see exactly how they are being integrated into the structure. I can
tell that define-macro is a literal symbol in the template, regardless
of any binding.

> and a little quiz:
>
>   (let ((x '(a b c))) ``(,,x ,@,x ,,@x ,@,@x))   => ??

The result is the equivalent of this object (itself, not its value):

 `(,(a b c) ,@(a b c) ,a ,b ,c ,@a ,@b ,@c)

The ,x's are straightforward; they are simply replaced by (a b c).  If
we look at in in the Scheme way, the splicing ,@x's under under an
unquote or unquote-splicing operator effectively cause it to have
multiple arguments. Both operators apply the same evaluation each of
their arguments, and then splice in the resulting values, resulting in
a distributive law: (unquote a b c) means the same thing as (unquote
a) (unquote b) (unquote c), and by means of this reduction to single-
argument forms, we can turn it back into the comma notation ,a ,b ,c.

I simply remember the distributive law in terms of the shorthand
operators themselves. ,,@x means that x is spliced in, and the inner
comma distributes into the elements of the splice.

Nested backquote is indeed something you have to ``get'', and that can
take time.
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <dd6d0372-0cb6-4711-afc3-72eb3a4799c3@s19g2000prg.googlegroups.com>
Let me point out that the simplicity of defmacro is
sometimes exaggerated when compared to define-syntax.
For example, the following let-macro

 (define-syntax let
    (syntax-rules ()
      ((_ ((x v) ...) b1 b2 ...)
       ((lambda (x ...) b1 b2 ...) v ...))))

is /not/ the same as the superficially simple

  (define-macro (let bindings . body)
    `((lambda ,(map car bindings) ,@body) ,@(map cdr bindings)))

but rather expresses the following:

  (define-macro (let . rest)
    (unless
      (and (list? rest)
           (>= (length rest) 2))
      (syntax-error 'let
         "Does not match (((x v) ...) b1 b2 ...)" rest))
    (unless
      (and (list? (car rest))
           (andmap (lambda (binding)
                     (= (length binding) 2))
                   (car rest)))
       (syntax-error 'let
          "Does not match ((x v) ...)" (car rest)))
     `((lambda ,(map car (car rest)) ,@(cdr rest))
        ,@(map cdr (car rest))))

Andre
From: Abdulaziz Ghuloum
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fp4org$lad$1@aioe.org>
············@yahoo.com wrote:

>       (and (list? (car rest))
>            (andmap (lambda (binding)

                        (and (list? binding)

>                      (= (length binding) 2))
>                    (car rest)))
>        (syntax-error 'let
>           "Does not match ((x v) ...)" (car rest)))
>      `((lambda ,(map car (car rest)) ,@(cdr rest))
>         ,@(map cdr (car rest))))
> 
> Andre
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <61mdiaF1vr523U1@mid.individual.net>
············@yahoo.com wrote:
> Let me point out that the simplicity of defmacro is
> sometimes exaggerated when compared to define-syntax.
> For example, the following let-macro
> 
>  (define-syntax let
>     (syntax-rules ()
>       ((_ ((x v) ...) b1 b2 ...)
>        ((lambda (x ...) b1 b2 ...) v ...))))
> 
> is /not/ the same as the superficially simple
> 
>   (define-macro (let bindings . body)
>     `((lambda ,(map car bindings) ,@body) ,@(map cdr bindings)))
> 
> but rather expresses the following:
> 
>   (define-macro (let . rest)
>     (unless
>       (and (list? rest)
>            (>= (length rest) 2))
>       (syntax-error 'let
>          "Does not match (((x v) ...) b1 b2 ...)" rest))
>     (unless
>       (and (list? (car rest))
>            (andmap (lambda (binding)
>                      (= (length binding) 2))
>                    (car rest)))
>        (syntax-error 'let
>           "Does not match ((x v) ...)" (car rest)))
>      `((lambda ,(map car (car rest)) ,@(cdr rest))
>         ,@(map cdr (car rest))))

Too complicated.

(defmacro let ((&rest bindings) &body body)
   (loop for (var val . rest) in bindings
         collect var into vars
         collect val into vals
         do (assert (null rest) ()
              "Too many values for ~S." var)
         finally (return `((lambda ,vars ,@body) ,@vals))))

LOOP is a pretty versatile tool for macro programming.

Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Jeff Barnett
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <47b60319$0$16658$4c368faf@roadrunner.com>
Pascal Costanza wrote:
> ············@yahoo.com wrote:
>> Let me point out that the simplicity of defmacro is
>> sometimes exaggerated when compared to define-syntax.
>> For example, the following let-macro
>>
>>  (define-syntax let
>>     (syntax-rules ()
>>       ((_ ((x v) ...) b1 b2 ...)
>>        ((lambda (x ...) b1 b2 ...) v ...))))
>>
>> is /not/ the same as the superficially simple
>>
>>   (define-macro (let bindings . body)
>>     `((lambda ,(map car bindings) ,@body) ,@(map cdr bindings)))
>>
>> but rather expresses the following:
>>
>>   (define-macro (let . rest)
>>     (unless
>>       (and (list? rest)
>>            (>= (length rest) 2))
>>       (syntax-error 'let
>>          "Does not match (((x v) ...) b1 b2 ...)" rest))
>>     (unless
>>       (and (list? (car rest))
>>            (andmap (lambda (binding)
>>                      (= (length binding) 2))
>>                    (car rest)))
>>        (syntax-error 'let
>>           "Does not match ((x v) ...)" (car rest)))
>>      `((lambda ,(map car (car rest)) ,@(cdr rest))
>>         ,@(map cdr (car rest))))
>
> Too complicated.
>
> (defmacro let ((&rest bindings) &body body)
>   (loop for (var val . rest) in bindings
>         collect var into vars
>         collect val into vals
>         do (assert (null rest) ()
>              "Too many values for ~S." var)
>         finally (return `((lambda ,vars ,@body) ,@vals))))
>
> LOOP is a pretty versatile tool for macro programming.
>
> Pascal
>
I'm Lisp curious, if there are any declarations (or strings) in the body 
portion of this macro, will the behavior of the let and the lambda be 
guaranteed identical?

-- Jeff Barnett
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <61o0rcF20j0pkU1@mid.individual.net>
Jeff Barnett wrote:
> Pascal Costanza wrote:
>> (defmacro let ((&rest bindings) &body body)
>>   (loop for (var val . rest) in bindings
>>         collect var into vars
>>         collect val into vals
>>         do (assert (null rest) ()
>>              "Too many values for ~S." var)
>>         finally (return `((lambda ,vars ,@body) ,@vals))))
>>
>> LOOP is a pretty versatile tool for macro programming.
>>
>> Pascal
>>
> I'm Lisp curious, if there are any declarations (or strings) in the body 
> portion of this macro, will the behavior of the let and the lambda be 
> guaranteed identical?

Yes, including special declarations.


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Jeff Barnett
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <47b76b01$0$1101$4c368faf@roadrunner.com>
Pascal Costanza wrote:
> Jeff Barnett wrote:
>> Pascal Costanza wrote:
>>> (defmacro let ((&rest bindings) &body body)
>>>   (loop for (var val . rest) in bindings
>>>         collect var into vars
>>>         collect val into vals
>>>         do (assert (null rest) ()
>>>              "Too many values for ~S." var)
>>>         finally (return `((lambda ,vars ,@body) ,@vals))))
>>>
>>> LOOP is a pretty versatile tool for macro programming.
>>>
>>> Pascal
>>>
>> I'm Lisp curious, if there are any declarations (or strings) in the 
>> body portion of this macro, will the behavior of the let and the 
>> lambda be guaranteed identical?
>
> Yes, including special declarations.
>
>
> Pascal
>
The reason I asked was historical. When the common lisp standard was 
being debated, there was a difference. Declarations within a let could 
effect the calculation of binding presets; on the other hand, 
declarations in a lambda could not effect the evaluation of its 
arguments. Way back when, I argued that this was a semantic glitch. I'm 
glad to hear the problem was finally resolved.

-- Jeff Barnett
From: Kent M Pitman
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <upruwmmyw.fsf@nhplace.com>
[ comp.lang.lisp only; http://www.nhplace.com/kent/PFAQ/cross-posting.html ]

Jeff Barnett <······@ca.rr.com> writes:

> Pascal Costanza wrote:
> > Jeff Barnett wrote:
> >> Pascal Costanza wrote:
> >>> (defmacro let ((&rest bindings) &body body)
> >>>   (loop for (var val . rest) in bindings
> >>>         collect var into vars
> >>>         collect val into vals
> >>>         do (assert (null rest) ()
> >>>              "Too many values for ~S." var)
> >>>         finally (return `((lambda ,vars ,@body) ,@vals))))
> >>>
> >>> LOOP is a pretty versatile tool for macro programming.
> >>>
> >>> Pascal
> >>>
> >> I'm Lisp curious, if there are any declarations (or strings) in the
> >> body portion of this macro, will the behavior of the let and the
> >> lambda be guaranteed identical?
> >
> > Yes, including special declarations.
> >
> >
> > Pascal
> >
> The reason I asked was historical. When the common lisp standard was
> being debated, there was a difference. Declarations within a let could
> effect the calculation of binding presets; on the other hand,
> declarations in a lambda could not effect the evaluation of its
> arguments. Way back when, I argued that this was a semantic
> glitch. I'm glad to hear the problem was finally resolved.

Hmm.  My recollection is that Jeff is right.  I'll have to look into it
more.  I think the difference is related to the scope of the specials
onto the init values.  In some cases, I think the special can go into
the init value.  But maybe I'm misremembering.

I tried this in LWW 4.4.5 and LWW 5.0.1 and I was surprised by the answer.

 (let ((a 'outer))
   (declare (special a))
   (let ((a 'inner)) 
     ;; this a is lexical
     (let ((b a))
       (declare (special a))
       (list b (symbol-value 'a)))))
 => (INNER OUTER)

I would have expected the answer to be (OUTER OUTER), but maybe I'm wrong.
I don't have time investigate this right now, so I figured I'd put it up and
maybe someone could do the research while I was off doing other things. :)

But in any case, my point is that I think there are places where
  (let (...) (declare ...) ...)
is not the same as
  ((lambda (...) (declare ...)) ...)
becuase the declare is not spanning the declarations in the lambda case,
and might need to be.

Disclaimer: No one should take any of my "I think"'s in this as some 
 sort of claim of truth.  They're just my recollection and impression
 of the moment.  I reserve the right to change my mind.
From: Maciej Katafiasz
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fp858n$b5b$1@news.net.uni-c.dk>
Den Sat, 16 Feb 2008 19:43:35 -0500 skrev Kent M Pitman:

> I tried this in LWW 4.4.5 and LWW 5.0.1 and I was surprised by the
> answer.
> 
>  (let ((a 'outer))
>    (declare (special a))
>    (let ((a 'inner))
>      ;; this a is lexical
>      (let ((b a))
>        (declare (special a))
>        (list b (symbol-value 'a)))))
>  => (INNER OUTER)
> 
> I would have expected the answer to be (OUTER OUTER), but maybe I'm
> wrong. I don't have time investigate this right now, so I figured I'd
> put it up and maybe someone could do the research while I was off doing
> other things. :)

No actual research, but this is consistent with my expectations. I see 
declarations as happening conceptually at the same time as bindings, in 
which case b can't see the value of special a, as it doesn't exist at the 
time b is bound. Harder to decide would be what to do with a LET*, 
though, there I fail to have any consistent expectations and would have 
to consult the spec :)

Cheers,
Maciej
From: Kent M Pitman
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <upruwqh1i.fsf@nhplace.com>
Maciej Katafiasz <········@gmail.com> writes:

> Den Sat, 16 Feb 2008 19:43:35 -0500 skrev Kent M Pitman:
> 
> > I tried this in LWW 4.4.5 and LWW 5.0.1 and I was surprised by the
> > answer.
> > 
> >  (let ((a 'outer))
> >    (declare (special a))
> >    (let ((a 'inner))
> >      ;; this a is lexical
> >      (let ((b a))
> >        (declare (special a))
> >        (list b (symbol-value 'a)))))
> >  => (INNER OUTER)
> > 
> > I would have expected the answer to be (OUTER OUTER), but maybe I'm
> > wrong. I don't have time investigate this right now, so I figured I'd
> > put it up and maybe someone could do the research while I was off doing
> > other things. :)
> 
> No actual research, but this is consistent with my expectations.

I think it was not the rule for some time, perhaps in CLTL times.
Looks like we did fix it.  Must have left a bad taste in my mouth.
The prevailing issue was Issue DECLARATION-SCOPE:NO-HOISTING.
http://www.lispworks.com/documentation/HyperSpec/Issues/iss092_w.htm

> I see declarations as happening conceptually at the same time as
> bindings,

Well, that's my point.  Since there is no binding, it seems to me that
we language designers should have defaulted to applying to the whole
LET (since there is no binding to stop it) rather than the case of
interest is.

> in which case b can't see the value of special a, as it doesn't
> exist at the time b is bound.

Point of view, I suppose.  I think of the value of special A as
"always existing" since it is always accessible via symbol-value, a
clue that all specials with the same name share the same value cell.
The variables never come into existence, only the ability to reference
the variables.  That's different from lexical variables, which are new
every time you execute a binding.

So, to me, the only question is whether referencing that cell has been
turned back on.  That's a legitimate question (absent a spec). The spec
is clear, I just don't 100% like the definition.

But I think historically the behavior went back and forth, and it
looks like the present behavior does make the LET/LAMBDA thing
consistent, so I was wrong about worrying that wasn't so.

(At least I think that's how it all is.  It's late and I'm tired, so I
can still have made a mistake.)
From: Juho Snellman
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <878x1ktkst.fsf@vasara.proghammer.com>
Kent M Pitman <······@nhplace.com> writes:
> I tried this in LWW 4.4.5 and LWW 5.0.1 and I was surprised by the answer.
> 
>  (let ((a 'outer))
>    (declare (special a))
>    (let ((a 'inner)) 
>      ;; this a is lexical
>      (let ((b a))
>        (declare (special a))
>        (list b (symbol-value 'a)))))
>  => (INNER OUTER)
> 
> I would have expected the answer to be (OUTER OUTER), but maybe I'm wrong.
> I don't have time investigate this right now, so I figured I'd put it up and
> maybe someone could do the research while I was off doing other things. :)

Lispworks is correct. The inner SPECIAL A declaration is a free
declaration, and per 3.3.4:
  
  The scope of free declarations specifically does not include
  initialization forms for bindings established by the form containing
  the declarations.

-- 
Juho Snellman
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <beba542d-2baa-4f10-9c89-6b26351d118d@i29g2000prf.googlegroups.com>
On Feb 15, 4:12 pm, Pascal Costanza <····@p-cos.net> wrote:
> ············@yahoo.com wrote:
> > Let me point out that the simplicity of defmacro is
> > sometimes exaggerated when compared to define-syntax.
> > For example, the following let-macro
>
> >  (define-syntax let
> >     (syntax-rules ()
> >       ((_ ((x v) ...) b1 b2 ...)
> >        ((lambda (x ...) b1 b2 ...) v ...))))

> (defmacro let ((&rest bindings) &body body)
>    (loop for (var val . rest) in bindings
>          collect var into vars
>          collect val into vals
>          do (assert (null rest) ()
>               "Too many values for ~S." var)
>          finally (return `((lambda ,vars ,@body) ,@vals))))

This does not appear equivalent.  What happened to the elegant
failure if a binding is not a list, or has length less than 2?
Also, what happened to the test that the body not be empty?

Andre
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <61o1mfF20b3cmU1@mid.individual.net>
············@yahoo.com wrote:
> On Feb 15, 4:12 pm, Pascal Costanza <····@p-cos.net> wrote:
>> ············@yahoo.com wrote:
>>> Let me point out that the simplicity of defmacro is
>>> sometimes exaggerated when compared to define-syntax.
>>> For example, the following let-macro
>>>  (define-syntax let
>>>     (syntax-rules ()
>>>       ((_ ((x v) ...) b1 b2 ...)
>>>        ((lambda (x ...) b1 b2 ...) v ...))))
> 
>> (defmacro let ((&rest bindings) &body body)
>>    (loop for (var val . rest) in bindings
>>          collect var into vars
>>          collect val into vals
>>          do (assert (null rest) ()
>>               "Too many values for ~S." var)
>>          finally (return `((lambda ,vars ,@body) ,@vals))))
> 
> This does not appear equivalent.

Sure. This is Common Lisp, not Scheme. Things are expected to behave a 
bit different over here. (That's one thing Schemers seem to find hard to 
get: When Common Lispers say that defmacro is good, they mean defmacro, 
not define-macro. There are some strong differences between the Common 
Lisp version and the Scheme versions.)

> What happened to the elegant
> failure if a binding is not a list, or has length less than 2?
> Also, what happened to the test that the body not be empty?

- If a binding is not a list: That's covered by the destructuring 
expression in the LOOP form.

  (let (a b c) a)

*** - CAR: A is not a list

Actually, that's not what a Common Lisper would expect. A Common Lisper 
would expect that the variables are accepted anyway and implicitly bound 
to nil. This is easy to achieve. Define the following function:

(defun prepare-binding (binding)
   (if (consp binding) binding (list binding)))

And loop over (mapcar #'prepare-binding bindings) instead of just bindings.


- If a binding has length less than 2: A Common Lisper would expect an 
implicit binding to nil, and this is what happens here.

(let ((a)) a)
NIL

If you insist on being more strict, you can handle that case in 
prepare-binding.


- If the body is empty: Empty lambda bodies implicitly return nil. 
That's what Common Lispers would expect.

 >((lambda ()))
NIL

Again, if you insist on being more strict, just put an (assert body) in 
the beginning of the macro definition. You'll get a nice error message then.

The implicit rules are there to make programming with such constructs 
more convenient (and convenience is what new language constructs are all 
about). Syntax-rules is nice for simple macros, but as soon as you want 
to add more bells and whistles, it becomes harder to do so. (How do you 
localize the different cases how to treat the different variations of 
what a binding could look like?)

Scheme has a tendency to disapprove of bells and whistles, but Common 
Lisp encourages them. Whether that's a good idea or not is a subjective 
assessment.


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <4aaee21b-f84f-45b0-a6f3-16d214f0eec3@o10g2000hsf.googlegroups.com>
On Feb 16, 7:02 am, Pascal Costanza <····@p-cos.net> wrote:
> >> ············@yahoo.com wrote:
> >>> Let me point out that the simplicity of defmacro is
> >>> sometimes exaggerated when compared to define-syntax.
> >>>
> >>>  (define-syntax let
> >>>     (syntax-rules ()
> >>>       ((_ ((x v) ...) b1 b2 ...)
> >>>        ((lambda (x ...) b1 b2 ...) v ...))))
> >>>
> >> (defmacro let ((&rest bindings) &body body)
> >>    (loop for (var val . rest) in bindings
> >>          collect var into vars
> >>          collect val into vals
> >>          do (assert (null rest) ()
> >>               "Too many values for ~S." var)
> >>          finally (return `((lambda ,vars ,@body) ,@vals))))
>
> That's one thing Schemers seem to find hard to
> get: When Common Lispers say that defmacro is good, they mean defmacro,
> not define-macro.

Okay, but comparing the above syntax-rules to your defmacro,
I personally find the syntax-rules more concise and legible
(effectively only two lines of BNF-like notation).  YMMV.

> > What happened to the elegant
> > failure if a binding is not a list, or has length less than 2?
>
> - If a binding is not a list: That's covered by the destructuring
> expression in the LOOP form.
>
>   (let (a b c) a)
>
> *** - CAR: A is not a list

That's not quite what was meant by elegant failure, though...

> Actually, that's not what a Common Lisper would expect. A Common Lisper
> would expect that the variables are accepted anyway and implicitly bound
> to nil.
>
> - If a binding has length less than 2: A Common Lisper would expect an
> implicit binding to nil,

Good grief.

Here is an idiomatic way of expressing that, trivially, in Scheme
(R6RS).

(define-syntax let
  (lambda (form)
    (syntax-case form ()
      ((_ (b ...) e ...)
       (with-syntax
           ((((x v) ...)
             (map (lambda (b)
                    (syntax-case b ()
                      ((x v) (identifier? x) #'(x v))
                      ((x)   (identifier? x) #'(x '()))
                      (x     (identifier? x) #'(x '()))))
                  #'(b ...))))
         #'((lambda (x ...) e ...) v ...))))))

I don't think this is so much about fundamental properties of
macro systems as it is about programming style.
Pattern matching is just as easy to use in Lisp defmacros
as it is in Scheme, yet it has never caught on.
Why Lispers prefer not to use it, and many Schemers do,
is probably more of a cultural question than any
fundamental property of defmacro.
One could just as well ask why Schemers themselves like to use
patterns for macros yet prefer not to use pattern matching for
function definitions as in ML.

Andre
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <61oqj9F20mvcuU1@mid.individual.net>
············@yahoo.com wrote:
> On Feb 16, 7:02 am, Pascal Costanza <····@p-cos.net> wrote:
>>>> ············@yahoo.com wrote:
>>>>> Let me point out that the simplicity of defmacro is
>>>>> sometimes exaggerated when compared to define-syntax.
>>>>>
>>>>>  (define-syntax let
>>>>>     (syntax-rules ()
>>>>>       ((_ ((x v) ...) b1 b2 ...)
>>>>>        ((lambda (x ...) b1 b2 ...) v ...))))
>>>>>
>>>> (defmacro let ((&rest bindings) &body body)
>>>>    (loop for (var val . rest) in bindings
>>>>          collect var into vars
>>>>          collect val into vals
>>>>          do (assert (null rest) ()
>>>>               "Too many values for ~S." var)
>>>>          finally (return `((lambda ,vars ,@body) ,@vals))))
>> That's one thing Schemers seem to find hard to
>> get: When Common Lispers say that defmacro is good, they mean defmacro,
>> not define-macro.
> 
> Okay, but comparing the above syntax-rules to your defmacro,
> I personally find the syntax-rules more concise and legible
> (effectively only two lines of BNF-like notation).  YMMV.

Sure, for small and simple macros, syntax-rules is better. I'm not 
convinced about more complex macros. (Schemers seem to have a tendency 
towards a stronger functional programming style, so that may not be as 
important then.)

>>> What happened to the elegant
>>> failure if a binding is not a list, or has length less than 2?
>> - If a binding is not a list: That's covered by the destructuring
>> expression in the LOOP form.
>>
>>   (let (a b c) a)
>>
>> *** - CAR: A is not a list
> 
> That's not quite what was meant by elegant failure, though...

What is inelegant about that?

>> Actually, that's not what a Common Lisper would expect. A Common Lisper
>> would expect that the variables are accepted anyway and implicitly bound
>> to nil.
>>
>> - If a binding has length less than 2: A Common Lisper would expect an
>> implicit binding to nil,
> 
> Good grief.
> 
> Here is an idiomatic way of expressing that, trivially, in Scheme
> (R6RS).
> 
> (define-syntax let
>   (lambda (form)
>     (syntax-case form ()
>       ((_ (b ...) e ...)
>        (with-syntax
>            ((((x v) ...)
>              (map (lambda (b)
>                     (syntax-case b ()
>                       ((x v) (identifier? x) #'(x v))
>                       ((x)   (identifier? x) #'(x '()))
>                       (x     (identifier? x) #'(x '()))))
>                   #'(b ...))))
>          #'((lambda (x ...) e ...) v ...))))))

See? Now the Scheme macro becomes more complicated as well...

> I don't think this is so much about fundamental properties of
> macro systems as it is about programming style.

Agreed.

> Pattern matching is just as easy to use in Lisp defmacros
> as it is in Scheme, yet it has never caught on.
> Why Lispers prefer not to use it, and many Schemers do,
> is probably more of a cultural question than any
> fundamental property of defmacro.

Right.

> One could just as well ask why Schemers themselves like to use
> patterns for macros yet prefer not to use pattern matching for
> function definitions as in ML.

As I said elsewhere in this thread (I think), syntax-rules is nice for 
simple cases, which is exactly what you need for example in papers or 
other situations where you want to illustrate something in neat and 
brief ways. I guess, syntax-rules is probably also somewhat nicer to 
read and understand by non-Lispers/Schemers than define-macro/defmacro, 
which helps for exposition as well.

In practical settings (and when not being fixated on a functional 
programming style), you need a 'real' macro system (whichever concrete 
macro system that may be). The reason is that it's more important that 
the macros are convenient to use, rather than that it's convenient to 
write those macros.


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <5b8c7bc6-fba8-4933-81be-c5715ce8fd21@n75g2000hsh.googlegroups.com>
On Feb 16, 2:07 pm, Pascal Costanza <····@p-cos.net> wrote:
> ············@yahoo.com wrote:

> >> *** - CAR: A is not a list
>
> > That's not quite what was meant by elegant failure, though...
>
> What is inelegant about that?

The message does not even indicate that the error was a syntax error.

> As I said elsewhere in this thread (I think), syntax-rules is nice for
> simple cases, which is exactly what you need for example in papers or
> other situations where you want to illustrate something in neat and
> brief ways. I guess, syntax-rules is probably also somewhat nicer to
> read and understand by non-Lispers/Schemers than define-macro/defmacro,
> which helps for exposition as well.
>
> In practical settings (and when not being fixated on a functional
> programming style), you need a 'real' macro system (whichever concrete
> macro system that may be). The reason is that it's more important that
> the macros are convenient to use, rather than that it's convenient to
> write those macros.

As has been said elsewhere, Scheme has, for years, had 'real' macro
systems that are not syntax-rules, making macros convenient to write
and
use.  The Scheme example I wrote of the generalized binding type LET
was
certainly not written in syntax-rules.  Comparing defmacro to syntax-
rules
is simply being out of date.  Scheme macros are considered by Schemers
to
be more robust than Lisp defmacros, given the referential
transparency
guarantees of Scheme macros, although I know Lispers tend not to care
about this issue.

Andre
From: John Thingstad
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <op.t6m8qlo7ut4oq5@pandora.alfanett.no>
P� Sat, 16 Feb 2008 21:32:26 +0100, skrev <············@yahoo.com>:

> is simply being out of date.  Scheme macros are considered by Schemers
> to be more robust than Lisp defmacros, given the referential
> transparency guarantees of Scheme macros, although I know Lispers tend  
> not to care
> about this issue.
>

We care. We just take care of it through protocol of writing.
gensym is a bit lightweight. With the help of a couple of macroes named  
'with-unique-names' and 'rebinding' it is fairly easy to write  
referentially transparent code. Rebinding for rebinding input variables so  
they are evaluated before use. with-unique-values for introducing new  
variables.

(defmacro lister (p q)
    (with-unique-names (x y)
       `(let ((,x (x-function))
              (,y (y-function)))
           (list ,p ,q ,x ,y))))

the form (lister i j) macroexpands to

(LET* ((#:X-88 (X-FUNCTION))
        (#:Y-89 (Y-FUNCTION)))
           (LIST i j #:X-88 #:Y-89))

(defmacro lister (x y)
    (rebinding (x y)
       '(list ,x ,y)))

the form (lister i j) macroexpands to

(LET* ((#:X-77 I)
        (#:Y-78 J))
           (LIST #:X-77 #:Y-78))

This seems to cover most cases.

--------------
John Thingstad
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <61phpoF1vki7aU1@mid.individual.net>
John Thingstad wrote:
> P� Sat, 16 Feb 2008 21:32:26 +0100, skrev <············@yahoo.com>:
> 
>> is simply being out of date.  Scheme macros are considered by Schemers
>> to be more robust than Lisp defmacros, given the referential
>> transparency guarantees of Scheme macros, although I know Lispers tend 
>> not to care
>> about this issue.
>>
> 
> We care. We just take care of it through protocol of writing.
> gensym is a bit lightweight. With the help of a couple of macroes named 
> 'with-unique-names' and 'rebinding' it is fairly easy to write 
> referentially transparent code. Rebinding for rebinding input variables 
> so they are evaluated before use. with-unique-values for introducing new 
> variables.
[...]

> This seems to cover most cases.

No, that's not enough. What you list here solves the problems of 
unintended variable capture, and order and number of evaluations. 
Referential transparency is something else, though.

Consider:

(let ((x 42))
   (macrolet ((foo () 'x))
     (let ((x 4711))
       (foo))))

Now assume you're not allowed to change the names of the x variable 
bindings. In a defmacro-style macro system, there is no way that you can 
ensure that the code to which foo expands refers to the outer x by just 
changing the macro definition. Whatever you may try, the outer x will be 
shadowed by the inner x in the inner expansion of foo.

Hygienic macro systems solve this issue. The following evaluates to 42:

(let ((x 42))
   (let-syntax ((foo (syntax-rules () ((foo) x))))
     (let ((x 4711))
       (foo))))

The problem can be relatively easily circumvented in Common Lisp by 
using the package system and choosing names more carefully. After all, 
the following actually does what you expect:

(let ((x 42))
   (macrolet ((foo () 'x))
     (let ((y 4711)) ; note: name changed
       (foo))))

If Common Lisp had a module system instead of a package system, and if 
Common Lisp were a Lisp-1 instead of a Lisp-2, referential transparency 
would be a much more pressing issue. [1]

Nevertheless, hygienic macro systems are strictly more powerful in that 
regard than defmacro-style macro systems.



Pascal

[1] That's the main reason why I personally prefer packages over modules 
and Lisp-2 over Lisp-1, because I get much less nameclashes with that in 
general (not only in macros).

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Rob Warnock
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <G4Wdnb26sovtKCranZ2dnUVZ_rmjnZ2d@speakeasy.net>
Pascal Costanza  <··@p-cos.net> wrote:
+---------------
| (let ((x 42))
|    (macrolet ((foo () 'x))
|      (let ((x 4711))
|        (foo))))
| 
| Now assume you're not allowed to change the names of the x variable 
| bindings. In a defmacro-style macro system, there is no way that you can 
| ensure that the code to which foo expands refers to the outer x by just 
| changing the macro definition. Whatever you may try, the outer x will be 
| shadowed by the inner x in the inner expansion of foo.
+---------------

Not to disagree with your point about macro scope & shadowing,
but this paticular example is not at all compelling, since you
could easily have gotten the desired result with no macros at all!

    > (let ((x 42))
	(flet ((foo () x))
	  (let ((x 4711))
	    (foo))))

    42
    > (let ((x 42))
	(flet ((foo () x))
	  (let ((x 4711))
	    (flet ((bar () x))
	      (let ((x 937))
		(list (foo) (bar) x))))))

    (42 4711 937)
    > 

Look, Ma, no macros!

Sometimes I think that with all the bickering about macro style
we sometimes forget that Scheme & CL both share the amazing power
of lexical closures.

+---------------
| Hygienic macro systems solve this issue.
+---------------

But so do closures... and with less "new syntax".


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Abdulaziz Ghuloum
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fp8k9a$ep5$1@aioe.org>
Rob Warnock wrote:

> Not to disagree with your point about macro scope & shadowing,
> but this paticular example is not at all compelling, since you
> could easily have gotten the desired result with no macros at all!

Of course.  His example was the simplest example to illustrate the
point.

>     (42 4711 937)
>     > 
> 
> Look, Ma, no macros!

Right, you can get the same thing by simply saying '(42 7411 937).
You don't need procedures or macros or anything really for that.

> Sometimes I think that with all the bickering about macro style
> we sometimes forget that Scheme & CL both share the amazing power
> of lexical closures.

In scheme, there is lexical scope for procedures and macros.  In CL,
there is lexical scope for procedures and dynamic scope for macros.
In elisp, it's dynamic scope for both (no closures).


Aziz,,,

PS. I'm ignoring dynamic variables, fluid-let, parameterize, etc.
From: Rob Warnock
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <2pSdnXKw5LzYaSranZ2dnUVZ_s-pnZ2d@speakeasy.net>
Abdulaziz Ghuloum  <········@cee.ess.indiana.edu> wrote:
+---------------
| Rob Warnock wrote:
| > Sometimes I think that with all the bickering about macro style
| > we sometimes forget that Scheme & CL both share the amazing power
| > of lexical closures.
| 
| In scheme, there is lexical scope for procedures and macros.  In CL,
| there is lexical scope for procedures and dynamic scope for macros.
| In elisp, it's dynamic scope for both (no closures).
+---------------

Hmmm... Digging into this a bit, I think that for CL, it's actually a
bit *worse*[1] than if it were really just "dynamic scope for macros":

    http://alu.org/HyperSpec/Body/speope_fletcm_scm_macrolet.html
    Special Operator FLET, LABELS, MACROLET
    ...
    macrolet
    The macro-expansion functions defined by macrolet are defined in the
    lexical environment in which the macrolet form appears. Declarations
    and macrolet and symbol-macrolet definitions affect the local macro
    definitions in a macrolet, but the consequences are undefined if
    the local macro definitions reference any local variable or function
    bindings that are visible in that lexical environment.

And then they give an example that is very close to Pascal_C's, except
using the LAMBDA-bound variables of a DEFUN as the outer ones that
can't be referenced instead of Pascal's LET-bound outer variable.

To repeat what Pascal Costanza <··@p-cos.net> wrote:
+---------------
| (let ((x 42))
|    (macrolet ((foo () 'x))
|      (let ((x 4711))
|        (foo))))
| 
| Now assume you're not allowed to change the names of the x variable 
| bindings. In a defmacro-style macro system, there is no way that you can 
| ensure that the code to which foo expands refers to the outer x by just 
| changing the macro definition. Whatever you may try, the outer x will be 
| shadowed by the inner x in the inner expansion of foo.
+---------------

After reading the above CLHS quote, I now think that's probably correct.
The MACROLET definition cannot itself capture the lexical value of the
outer X [because it probably doesn't exist yet when the macro expansion
function is closed over]. You would have to use some *other* binding
form to perform that capture at :EXECUTE time [such as the FLETs I
showed previously], but then the MACROLET definition could certainly
expand into a *reference* to that other binding form. And the definition
of the macro expansion of that reference can even be done *before* the
other binding form is encountered:

    > (let ((x 42))
	(macrolet ((foo () '(list y x)))
	  (let ((y x))
	    (let ((x 4711))
	      (foo)))))

    (42 4711)
    >

*Or* after:

    > (let ((x 42))
	(let ((y x))
	  (macrolet ((foo () '(list y x)))
	    (let ((x 4711))
	      (foo)))))

    (42 4711)
    >

But the point being that in either case the macro *definition* cannot
reference the :EXECUTE lexical environment, only its *expansion* can.

Oh, well...


-Rob

[1] The reason I say this is "worse" than "just dynamic scope" is that
    the dynamic values of variables in the macro *definition* might be
    those at compile time, which could be altogether different than the
    dynamic values of those very same variables at runtime (:EXECUTE).
    Pascal Bourguignon's article in the "passing values from compile-time
    to load-time" thread <···················@thalassa.informatimago.com>
    hints at this when he said:

	When a macro is executing, the situation is :EXECUTE.

    but I don't think he made it clear enough there -- at least, not
    for the purposes of *this* discussion -- that the macro is probably
    executing at compile time, and even though "the situation is :EXECUTE"
    during its execution the dynamic environment at that time is the
    environment of the *compiler*, which is not (or not necessarily)
    the dynamic environment in which the code being compiled will
    itself :EXECUTE.

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Abdulaziz Ghuloum
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fp90g3$pg1$1@aioe.org>
Rob Warnock wrote:

> But the point being that in either case the macro *definition*
> cannot reference the :EXECUTE lexical environment, only its 
> *expansion* can.

That's consistent with Scheme.

 > (let ((x 5))
     (let-syntax ((f (lambda (stx) x)))
       (let ((x 6))
         (f))))
=>
Unhandled exception
  Condition components:
    1. &who: x
    2. &message: "identifier out of context"
    3. &syntax:
        form: x

But:

 > (let ((x 5))
     (let-syntax ((f (lambda (stx) #'x)))
       (let ((x 6))
         (f))))
=> 5

The syntax object obtained by #'x contains a lexical environment
which closes over all lexical identifiers visible at that point
(it contains a mapping from x to the outer x among other things).

In Pascal's example:

 > (let ((x 5))
     (macrolet ((f () 'x))
       (let ((x 6))
         (f))))
=> 6

The x in f is just a symbol.  It has no lexical environment
attached to it.  The expansion of (f) will use the environment
at the macro use site (e.g., where (f) occurred) and not the
macro definition site (where the 'x occurred).
From: Abdulaziz Ghuloum
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fp9719$dps$1@aioe.org>
Abdulaziz Ghuloum wrote:

> The syntax object obtained by #'x contains a lexical environment
> which closes over all lexical identifiers visible at that point
> (it contains a mapping from x to the outer x among other things).

Just to drive the point home.  Suppose Scheme had a macrolet[*],
then we can write:

 > (let ((x 'outer-x))
     (macrolet ((f () #'x))
       (let ((x 'inner-x))
         (list x (f)))))
=>
(inner-x outer-x)

I said that #'x contains an environment that contains all
lexically visible identifiers at that point.  Scheme has the
procedure datum->syntax that attaches the environment of one
identifier to any s-expression, in essence, obtaining an
expression as if it had been written in the location where
the identifier occurred.

 > (let ((x 'outer-x) (y 'outer-y))
     (macrolet ((f (sym) (datum->syntax #'here sym)))
       (let ((x 'inner-x) (y 'inner-y))
         (list x y (f x) (f y)))))
=>
(inner-x inner-y outer-x outer-y)

The syntax object obtained from #'here has a lexical closure
which contains the bindings of the outer x and y among other
things.  The macro call (f x) attaches the #'here environment
to the symbol x.  The result is an identifier x as if it had
occurred in place of the #'here, which is the outer x.

I hope this clarifies things a bit.

Aziz,,,



[*]  This is the Scheme macrolet that I'm using for these
examples:

(define-syntax macrolet
   (syntax-rules ()
     ((_ ((names (args ...) exprs) ...) b b* ...)
      (let-syntax ((names
                    (lambda (stx)
                      (syntax-case stx ()
                        ((_ args ...)
                         (let ((args (syntax->datum #'args)) ...)
                           exprs)))))
                   ...)
        b b* ...))))
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <61qpc9F20nivdU1@mid.individual.net>
Abdulaziz Ghuloum wrote:
> In Pascal's example:
> 
>  > (let ((x 5))
>     (macrolet ((f () 'x))
>       (let ((x 6))
>         (f))))
> => 6
> 
> The x in f is just a symbol.  It has no lexical environment
> attached to it.  The expansion of (f) will use the environment
> at the macro use site (e.g., where (f) occurred) and not the
> macro definition site (where the 'x occurred).

To explain how this is solved in Common Lisp: There are essentially two 
cases, either local or global macro definitions.

The example above is a local macro. It's not really an interesting case 
in practice because of that, because all the code there belongs to you 
anyway. So just rename one of the x's, and you're done.

For global macros, let's assume for a while we have lexically global 
variables: [1]

(defglobal x 5)

(defmacro f () 'x)

(let ((x 6)) (f)) => 6

This code still has the problem that f is not referentially transparent. 
However, you can use the package system to solve that problem. Again, 
there are two cases: Either (a) you don't export the variable x, or (b) 
you export it.

(a)

(defpackage my-library
   (:export f)) ;; note: x not exported

(in-package my-library)

(defglobal x 5)

(defmacro f () 'x)


(defpackage my-client-code
   (:use my-library))

(in-package my-client-code)

(let ((x 6)) (f)) => 5

Here, the problem doesn't occur anymore because my-library::x and 
my-client-code::x are different symbols! (That's why a package system 
makes writing such macros more reliable. In a module system, the two 
symbols would be the same and you would still have the problem!)

(b)

(defpackage my-library
   (:export f x)) ;; note: both f and x exported

(in-package my-library)

(defglobal x 5)

(defmacro f () 'x)


(defpackage my-client-code
   (:use my-library))

(in-package my-client-code)

(let ((x 6)) (f)) => 6

Here, the problem seems to occur, BUT: Since x is exported, the ability 
to rebind it becomes part of the interface (the "API") of my-library, 
it's one of the operations you can "perform" on such names. So it's the 
responsibility of my-library to _document_ what happens in such cases 
and to point out that there are possible interactions with f (or 
reorganize the code such that such interactions don't occur).

Another important point here is that as soon as you export symbols from 
a package, it's a good idea to use more convincing names than f and x 
(and in practice, this is where using 
long-and-descriptive-names-for-your-identifiers pays off, as is 
typically done in Common Lisp).


I think this analysis covers all important cases, and it shows that the 
problem doesn't really exist in practice, or at least doesn't hurt that 
much. Note that this comes from the fact that Common Lisp has a package 
system, not a module system. The fact that Common Lisp is a Lisp-2 also 
plays a role here (but I haven't covered that part in my discussion).

In a module system, all definitions are always 'local', in a sense. 
That's why the problem is much more pressing in Scheme...



Pascal

[1] Google for defglobal to see how to implement that in Common Lisp. 
Discussing global lexicals makes the point a bit clearer, but the 
discussion also holds for other lexical entities (like functions).

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Ron Garret
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <rNOSPAMon-16ADCE.09365717022008@news.gha.chartermi.net>
In article <···············@mid.individual.net>,
 Pascal Costanza <··@p-cos.net> wrote:

> Abdulaziz Ghuloum wrote:
> > In Pascal's example:
> > 
> >  > (let ((x 5))
> >     (macrolet ((f () 'x))
> >       (let ((x 6))
> >         (f))))
> > => 6
> > 
> > The x in f is just a symbol.  It has no lexical environment
> > attached to it.  The expansion of (f) will use the environment
> > at the macro use site (e.g., where (f) occurred) and not the
> > macro definition site (where the 'x occurred).
> 
> To explain how this is solved in Common Lisp: There are essentially two 
> cases, either local or global macro definitions.
> 
> The example above is a local macro. It's not really an interesting case 
> in practice because of that, because all the code there belongs to you 
> anyway. So just rename one of the x's, and you're done.
> 
> For global macros, let's assume for a while we have lexically global 
> variables: [1]
> 
> (defglobal x 5)
> 
> (defmacro f () 'x)
> 
> (let ((x 6)) (f)) => 6
> 
> This code still has the problem that f is not referentially transparent. 
> However, you can use the package system to solve that problem.

Or you can solve it this way:

(defmacro f () x)

Or, if you don't trust your implementation to do the Right Thing with 
lexical scope in macro definitions (because the spec doesn't actually 
require it to):

(defun my-macro-expander () x)

(defmacro f () (my-macro-expander))

rg
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <61rc54F20tei4U1@mid.individual.net>
Ron Garret wrote:
> In article <···············@mid.individual.net>,
>  Pascal Costanza <··@p-cos.net> wrote:
> 
>> Abdulaziz Ghuloum wrote:
>>> In Pascal's example:
>>>
>>>  > (let ((x 5))
>>>     (macrolet ((f () 'x))
>>>       (let ((x 6))
>>>         (f))))
>>> => 6
>>>
>>> The x in f is just a symbol.  It has no lexical environment
>>> attached to it.  The expansion of (f) will use the environment
>>> at the macro use site (e.g., where (f) occurred) and not the
>>> macro definition site (where the 'x occurred).
>> To explain how this is solved in Common Lisp: There are essentially two 
>> cases, either local or global macro definitions.
>>
>> The example above is a local macro. It's not really an interesting case 
>> in practice because of that, because all the code there belongs to you 
>> anyway. So just rename one of the x's, and you're done.
>>
>> For global macros, let's assume for a while we have lexically global 
>> variables: [1]
>>
>> (defglobal x 5)
>>
>> (defmacro f () 'x)
>>
>> (let ((x 6)) (f)) => 6
>>
>> This code still has the problem that f is not referentially transparent. 
>> However, you can use the package system to solve that problem.
> 
> Or you can solve it this way:
> 
> (defmacro f () x)
> 
> Or, if you don't trust your implementation to do the Right Thing with 
> lexical scope in macro definitions (because the spec doesn't actually 
> require it to):
> 
> (defun my-macro-expander () x)
> 
> (defmacro f () (my-macro-expander))

A definition like (defmacro f () 'x) ensures that the variable lookup to 
which this macro expands is done at runtime (or better, at the execution 
time of the code into which it expands). A definition like (defmacro f 
() x) will perform the lookup of x at macro-expansion time. For 
interpreted code, that does not make a big difference, but for compiled 
code, it certainly does: Macro-expansion time and compile item is 
practically the same for compiled code, and the respective lexical 
bindings will generally simply not exist yet at compile time.

That the spec doesn't require macro functions to respect lexical scoping 
is nonsense: ANSI Common Lisp is exceptionally clear in that regard. 
Just look up the entries for defmacro and macrolet in the HyperSpec.


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Ron Garret
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <rNOSPAMon-866758.11111817022008@news.gha.chartermi.net>
In article <···············@mid.individual.net>,
 Pascal Costanza <··@p-cos.net> wrote:

> Ron Garret wrote:
> > In article <···············@mid.individual.net>,
> >  Pascal Costanza <··@p-cos.net> wrote:
> > 
> >> Abdulaziz Ghuloum wrote:
> >>> In Pascal's example:
> >>>
> >>>  > (let ((x 5))
> >>>     (macrolet ((f () 'x))
> >>>       (let ((x 6))
> >>>         (f))))
> >>> => 6
> >>>
> >>> The x in f is just a symbol.  It has no lexical environment
> >>> attached to it.  The expansion of (f) will use the environment
> >>> at the macro use site (e.g., where (f) occurred) and not the
> >>> macro definition site (where the 'x occurred).
> >> To explain how this is solved in Common Lisp: There are essentially two 
> >> cases, either local or global macro definitions.
> >>
> >> The example above is a local macro. It's not really an interesting case 
> >> in practice because of that, because all the code there belongs to you 
> >> anyway. So just rename one of the x's, and you're done.
> >>
> >> For global macros, let's assume for a while we have lexically global 
> >> variables: [1]
> >>
> >> (defglobal x 5)
> >>
> >> (defmacro f () 'x)
> >>
> >> (let ((x 6)) (f)) => 6
> >>
> >> This code still has the problem that f is not referentially transparent. 
> >> However, you can use the package system to solve that problem.
> > 
> > Or you can solve it this way:
> > 
> > (defmacro f () x)
> > 
> > Or, if you don't trust your implementation to do the Right Thing with 
> > lexical scope in macro definitions (because the spec doesn't actually 
> > require it to):
> > 
> > (defun my-macro-expander () x)
> > 
> > (defmacro f () (my-macro-expander))
> 
> A definition like (defmacro f () 'x) ensures that the variable lookup to 
> which this macro expands is done at runtime (or better, at the execution 
> time of the code into which it expands).

Then it's not lexically scoped.  I thought the whole point of the 
present exercise was to get X to refer to the lexically apparent binding 
at the point of macro definition.

> A definition like (defmacro f 
> () x) will perform the lookup of x at macro-expansion time.

Yes.  Isn't that exactly what you want in this case?  (Maybe I've 
dropped some context here.)

> For 
> interpreted code, that does not make a big difference, but for compiled 
> code, it certainly does: Macro-expansion time and compile item is 
> practically the same for compiled code, and the respective lexical 
> bindings will generally simply not exist yet at compile time.

Of course they will.  Compile-time for the invoker of the macro *is* 
run-time for the macroexpander function, so any lexical bindings in the 
macro expander function must exist at that point (otherwise by 
definition they are not lexical bindings).

> That the spec doesn't require macro functions to respect lexical scoping 
> is nonsense: ANSI Common Lisp is exceptionally clear in that regard. 
> Just look up the entries for defmacro and macrolet in the HyperSpec.

Yeah, it surprised me too.  I'm going off something Rob Warnock posted 
earlier in this thread:

    http://alu.org/HyperSpec/Body/speope_fletcm_scm_macrolet.html
    Special Operator FLET, LABELS, MACROLET
    ...
    macrolet
    The macro-expansion functions defined by macrolet are defined in the
    lexical environment in which the macrolet form appears. Declarations
    and macrolet and symbol-macrolet definitions affect the local macro
    definitions in a macrolet, but the consequences are undefined if
    the local macro definitions reference any local variable or function
    bindings that are visible in that lexical environment.

Maybe I misinterpreted what this section of the spec is saying.

rg
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <61rgpvF20icijU1@mid.individual.net>
Ron Garret wrote:
> In article <···············@mid.individual.net>,
>  Pascal Costanza <··@p-cos.net> wrote:
> 
>> Ron Garret wrote:
>>> In article <···············@mid.individual.net>,
>>>  Pascal Costanza <··@p-cos.net> wrote:
>>>
>>>> Abdulaziz Ghuloum wrote:
>>>>> In Pascal's example:
>>>>>
>>>>>  > (let ((x 5))
>>>>>     (macrolet ((f () 'x))
>>>>>       (let ((x 6))
>>>>>         (f))))
>>>>> => 6
>>>>>
>>>>> The x in f is just a symbol.  It has no lexical environment
>>>>> attached to it.  The expansion of (f) will use the environment
>>>>> at the macro use site (e.g., where (f) occurred) and not the
>>>>> macro definition site (where the 'x occurred).
>>>> To explain how this is solved in Common Lisp: There are essentially two 
>>>> cases, either local or global macro definitions.
>>>>
>>>> The example above is a local macro. It's not really an interesting case 
>>>> in practice because of that, because all the code there belongs to you 
>>>> anyway. So just rename one of the x's, and you're done.
>>>>
>>>> For global macros, let's assume for a while we have lexically global 
>>>> variables: [1]
>>>>
>>>> (defglobal x 5)
>>>>
>>>> (defmacro f () 'x)
>>>>
>>>> (let ((x 6)) (f)) => 6
>>>>
>>>> This code still has the problem that f is not referentially transparent. 
>>>> However, you can use the package system to solve that problem.
>>> Or you can solve it this way:
>>>
>>> (defmacro f () x)
>>>
>>> Or, if you don't trust your implementation to do the Right Thing with 
>>> lexical scope in macro definitions (because the spec doesn't actually 
>>> require it to):
>>>
>>> (defun my-macro-expander () x)
>>>
>>> (defmacro f () (my-macro-expander))
>> A definition like (defmacro f () 'x) ensures that the variable lookup to 
>> which this macro expands is done at runtime (or better, at the execution 
>> time of the code into which it expands).
> 
> Then it's not lexically scoped.  I thought the whole point of the 
> present exercise was to get X to refer to the lexically apparent binding 
> at the point of macro definition.

Yes, but without evaluating it at macro-expansion time. That's the 
point: We want to have the cake and eat it at the same time. Not either 
or. And that's what hygienic macro systems allow you to do.

>> A definition like (defmacro f 
>> () x) will perform the lookup of x at macro-expansion time.
> 
> Yes.  Isn't that exactly what you want in this case?  (Maybe I've 
> dropped some context here.)

No, that's not what we want.

>> For 
>> interpreted code, that does not make a big difference, but for compiled 
>> code, it certainly does: Macro-expansion time and compile item is 
>> practically the same for compiled code, and the respective lexical 
>> bindings will generally simply not exist yet at compile time.
> 
> Of course they will.  Compile-time for the invoker of the macro *is* 
> run-time for the macroexpander function, so any lexical bindings in the 
> macro expander function must exist at that point (otherwise by 
> definition they are not lexical bindings).
> 
>> That the spec doesn't require macro functions to respect lexical scoping 
>> is nonsense: ANSI Common Lisp is exceptionally clear in that regard. 
>> Just look up the entries for defmacro and macrolet in the HyperSpec.
> 
> Yeah, it surprised me too.  I'm going off something Rob Warnock posted 
> earlier in this thread:
> 
>     http://alu.org/HyperSpec/Body/speope_fletcm_scm_macrolet.html
>     Special Operator FLET, LABELS, MACROLET
>     ...
>     macrolet
>     The macro-expansion functions defined by macrolet are defined in the
>     lexical environment in which the macrolet form appears. Declarations
>     and macrolet and symbol-macrolet definitions affect the local macro
>     definitions in a macrolet, but the consequences are undefined if
>     the local macro definitions reference any local variable or function
>     bindings that are visible in that lexical environment.
> 
> Maybe I misinterpreted what this section of the spec is saying.

I have the impression you misunderstand that section.

Consider this (tested under Allegro Common Lisp, because it macroexpands 
during evaluation in interpreted mode):

CL-USER(1): (defun test ()
               (let ((x 42))
                 (macrolet ((foo () (if (> x 20) 'y 'z)))
                   (let ((y 0) (z 1))
                     (foo)))))
TEST
CL-USER(2): (test)
0
CL-USER(3): (compile 'test)
; While compiling TEST:
Error: Attempt to take the value of the unbound variable `X'.
   [condition type: UNBOUND-VARIABLE]

What happens here is that when (foo) is invoked, only then the macro 
invocation is expanded. The macro function for foo is lexically scoped 
(as required by ANSI Common Lisp!), so it can see the local variable x.

However, when you compile the code, macroexpansion has to be fully 
performed at compile time (again as required by ANSI Common Lisp!). At 
macro expansion time, though, the binding for x doesn't exist yet. 
That's why it refuses to compile.

The fact that in interpreted mode this code works and in compiled mode 
it doesn't is why the spec says that "the consequences are undefined."

Compare the situation with this code:

CL-USER(1): (defun test2 ()
               (symbol-macrolet ((x 42))
                 (macrolet ((foo () (if (> x 20) 'y 'z)))
                   (let ((y 0) (z 1))
                     (foo)))))
TEST2
CL-USER(2): (test2)
0
CL-USER(3): (compile 'test2)
; While compiling TEST2:
Warning: Variable Z is never used.
TEST2
T
NIL
CL-USER(4): (test2)
0

Works fine, lexical scoping is respected perfectly, and all that... ;)


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Ron Garret
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <rNOSPAMon-73CB9A.12200417022008@news.gha.chartermi.net>
In article <···············@mid.individual.net>,
 Pascal Costanza <··@p-cos.net> wrote:

> >>> (defun my-macro-expander () x)
> >>>
> >>> (defmacro f () (my-macro-expander))
> >> A definition like (defmacro f () 'x) ensures that the variable lookup to 
> >> which this macro expands is done at runtime (or better, at the execution 
> >> time of the code into which it expands).
> > 
> > Then it's not lexically scoped.  I thought the whole point of the 
> > present exercise was to get X to refer to the lexically apparent binding 
> > at the point of macro definition.
> 
> Yes, but without evaluating it at macro-expansion time. That's the 
> point: We want to have the cake and eat it at the same time. Not either 
> or. And that's what hygienic macro systems allow you to do.

Ah.  Let me make sure I understand.  You want the following:

? (defglobal x 1)
1
? (defmacro m () x)
M
? (defun f () (m))
F
? (let ((x 2)) (f))
;Compiler warnings :
;   Unused lexical variable X, in an anonymous lambda form.
1

But then you also want:

? (setf x 2)
2
? (f)
2

(It actually returns 1 as things stand.)

Is that right?

(Just FYI, the reason I'm interested in understanding this is because I 
want to make macros do the Right Thing in my lexicon library.)


> I have the impression you misunderstand that section.

Could be.  I was under the impression that:

(macrolet ((foo () body)) ...

was equivalent to

(flet ((foo-expander () body))
  (macrolet ((foo () (foo-expander))

but I guess it isn't.  I need to go back and re-read some of this.

Thanks for the example.  That was very helpful.

rg
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <61rkgiF20bnkeU1@mid.individual.net>
Ron Garret wrote:
> In article <···············@mid.individual.net>,
>  Pascal Costanza <··@p-cos.net> wrote:
> 
>>>>> (defun my-macro-expander () x)
>>>>>
>>>>> (defmacro f () (my-macro-expander))
>>>> A definition like (defmacro f () 'x) ensures that the variable lookup to 
>>>> which this macro expands is done at runtime (or better, at the execution 
>>>> time of the code into which it expands).
>>> Then it's not lexically scoped.  I thought the whole point of the 
>>> present exercise was to get X to refer to the lexically apparent binding 
>>> at the point of macro definition.
>> Yes, but without evaluating it at macro-expansion time. That's the 
>> point: We want to have the cake and eat it at the same time. Not either 
>> or. And that's what hygienic macro systems allow you to do.
> 
> Ah.  Let me make sure I understand.  You want the following:
> 
> ? (defglobal x 1)
> 1
> ? (defmacro m () x)
> M
> ? (defun f () (m))
> F
> ? (let ((x 2)) (f))
> ;Compiler warnings :
> ;   Unused lexical variable X, in an anonymous lambda form.
> 1
> 
> But then you also want:
> 
> ? (setf x 2)
> 2
> ? (f)
> 2
> 
> (It actually returns 1 as things stand.)
> 
> Is that right?

Yes.

> (Just FYI, the reason I'm interested in understanding this is because I 
> want to make macros do the Right Thing in my lexicon library.)

Then you probably want hygienic macros. Look at Will Clinger's "Hygienic 
Macros Through Explicit Renaming" paper for a simple version.

>> I have the impression you misunderstand that section.
> 
> Could be.  I was under the impression that:
> 
> (macrolet ((foo () body)) ...
> 
> was equivalent to
> 
> (flet ((foo-expander () body))
>   (macrolet ((foo () (foo-expander))
> 
> but I guess it isn't.

Yes, it is. The second version has the same problem as the first one: 
foo-expander is only available at runtime, but not at compile time.

> I need to go back and re-read some of this.
> 
> Thanks for the example.  That was very helpful.

I'm happy that it helped...


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Ron Garret
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <rNOSPAMon-AF0DED.12494617022008@news.gha.chartermi.net>
In article <···············@mid.individual.net>,
 Pascal Costanza <··@p-cos.net> wrote:

> > (Just FYI, the reason I'm interested in understanding this is because I 
> > want to make macros do the Right Thing in my lexicon library.)
> 
> Then you probably want hygienic macros. Look at Will Clinger's "Hygienic 
> Macros Through Explicit Renaming" paper for a simple version.

Maybe.  I'm thinking there might be a sneakier solution though :-)

> >> I have the impression you misunderstand that section.
> > 
> > Could be.  I was under the impression that:
> > 
> > (macrolet ((foo () body)) ...
> > 
> > was equivalent to
> > 
> > (flet ((foo-expander () body))
> >   (macrolet ((foo () (foo-expander))
> > 
> > but I guess it isn't.
> 
> Yes, it is. The second version has the same problem as the first one: 
> foo-expander is only available at runtime, but not at compile time.

Ah.  Thanks, you just saved me a bunch of reading :-)

rg
From: Ron Garret
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <rNOSPAMon-A18EE1.10421619022008@news.gha.chartermi.net>
In article <·······························@news.gha.chartermi.net>,
 Ron Garret <·········@flownet.com> wrote:

> In article <···············@mid.individual.net>,
>  Pascal Costanza <··@p-cos.net> wrote:
> 
> > > (Just FYI, the reason I'm interested in understanding this is because I 
> > > want to make macros do the Right Thing in my lexicon library.)
> > 
> > Then you probably want hygienic macros. Look at Will Clinger's "Hygienic 
> > Macros Through Explicit Renaming" paper for a simple version.
> 
> Maybe.  I'm thinking there might be a sneakier solution though :-)

And I think I was right:

? (defglobal x 1)
1
? (macroexpand 'x)
(SYMBOL-VALUE '#:X)
T
? (defmacro foo () `',x)
FOO
? (foo)
1
? (setf x 2)
2
? (foo)
2
? (let ((x 3)) (foo))
;Compiler warnings :
;   Unused lexical variable X, in an anonymous lambda form.
2
? 

rg
From: Ron Garret
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <rNOSPAMon-48B2D3.11392919022008@news.gha.chartermi.net>
In article <·······························@news.gha.chartermi.net>,
 Ron Garret <·········@flownet.com> wrote:

> In article <·······························@news.gha.chartermi.net>,
>  Ron Garret <·········@flownet.com> wrote:
> 
> > In article <···············@mid.individual.net>,
> >  Pascal Costanza <··@p-cos.net> wrote:
> > 
> > > > (Just FYI, the reason I'm interested in understanding this is because I 
> > > > want to make macros do the Right Thing in my lexicon library.)
> > > 
> > > Then you probably want hygienic macros. Look at Will Clinger's "Hygienic 
> > > Macros Through Explicit Renaming" paper for a simple version.
> > 
> > Maybe.  I'm thinking there might be a sneakier solution though :-)
> 
> And I think I was right:
> 
> ? (defglobal x 1)
> 1
> ? (macroexpand 'x)
> (SYMBOL-VALUE '#:X)
> T
> ? (defmacro foo () `',x)
> FOO
> ? (foo)
> 1
> ? (setf x 2)
> 2
> ? (foo)
> 2
> ? (let ((x 3)) (foo))
> ;Compiler warnings :
> ;   Unused lexical variable X, in an anonymous lambda form.
> 2
> ? 
> 
> rg

Doh!  Belay that.  Try this instead:

? (defmacro foo () (macroexpand 'x))
FOO
? (foo)
2
? x
2
? (defun f () (foo))
F
? (f)
2
? (incf x)
3
? (f)
3
? (let ((x 4)) (f))
;Compiler warnings :
;   Unused lexical variable X, in an anonymous lambda form.
3
? 

Probably need to stick some &environment args in there to really make it 
work right.

rg
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <620r85F1tm3qeU1@mid.individual.net>
Ron Garret wrote:
> In article <·······························@news.gha.chartermi.net>,
>  Ron Garret <·········@flownet.com> wrote:
> 
>> In article <·······························@news.gha.chartermi.net>,
>>  Ron Garret <·········@flownet.com> wrote:
>>
>>> In article <···············@mid.individual.net>,
>>>  Pascal Costanza <··@p-cos.net> wrote:
>>>
>>>>> (Just FYI, the reason I'm interested in understanding this is because I 
>>>>> want to make macros do the Right Thing in my lexicon library.)
>>>> Then you probably want hygienic macros. Look at Will Clinger's "Hygienic 
>>>> Macros Through Explicit Renaming" paper for a simple version.
>>> Maybe.  I'm thinking there might be a sneakier solution though :-)
>> And I think I was right:
>>
> ? (defmacro foo () (macroexpand 'x))
> FOO
> ? (foo)
> 2
> ? x
> 2
> ? (defun f () (foo))
> F
> ? (f)
> 2
> ? (incf x)
> 3
> ? (f)
> 3
> ? (let ((x 4)) (f))
> ;Compiler warnings :
> ;   Unused lexical variable X, in an anonymous lambda form.
> 3
> ? 

I think you're still wrong:

(flet ((foo () 4))
   (f))
=> probably returns 4 now

If you want referential transparency, you should protect yourself 
against any kind of influence from the outside, not only from variables.


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Ron Garret
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <rNOSPAMon-0DECE6.12222919022008@news.gha.chartermi.net>
In article <···············@mid.individual.net>,
 Pascal Costanza <··@p-cos.net> wrote:

> Ron Garret wrote:
> > In article <·······························@news.gha.chartermi.net>,
> >  Ron Garret <·········@flownet.com> wrote:
> > 
> >> In article <·······························@news.gha.chartermi.net>,
> >>  Ron Garret <·········@flownet.com> wrote:
> >>
> >>> In article <···············@mid.individual.net>,
> >>>  Pascal Costanza <··@p-cos.net> wrote:
> >>>
> >>>>> (Just FYI, the reason I'm interested in understanding this is because I 
> >>>>> want to make macros do the Right Thing in my lexicon library.)
> >>>> Then you probably want hygienic macros. Look at Will Clinger's "Hygienic 
> >>>> Macros Through Explicit Renaming" paper for a simple version.
> >>> Maybe.  I'm thinking there might be a sneakier solution though :-)
> >> And I think I was right:
> >>
> > ? (defmacro foo () (macroexpand 'x))
> > FOO
> > ? (foo)
> > 2
> > ? x
> > 2
> > ? (defun f () (foo))
> > F
> > ? (f)
> > 2
> > ? (incf x)
> > 3
> > ? (f)
> > 3
> > ? (let ((x 4)) (f))
> > ;Compiler warnings :
> > ;   Unused lexical variable X, in an anonymous lambda form.
> > 3
> > ? 
> 
> I think you're still wrong:
> 
> (flet ((foo () 4))
>    (f))
> => probably returns 4 now
> 
> If you want referential transparency, you should protect yourself 
> against any kind of influence from the outside, not only from variables.

One thing at a time :-)

rg
From: Ron Garret
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <rNOSPAMon-97EC95.12254319022008@news.gha.chartermi.net>
In article <·······························@news.gha.chartermi.net>,
 Ron Garret <·········@flownet.com> wrote:

> In article <···············@mid.individual.net>,
>  Pascal Costanza <··@p-cos.net> wrote:
> 
> > Ron Garret wrote:
> > > In article <·······························@news.gha.chartermi.net>,
> > >  Ron Garret <·········@flownet.com> wrote:
> > > 
> > >> In article <·······························@news.gha.chartermi.net>,
> > >>  Ron Garret <·········@flownet.com> wrote:
> > >>
> > >>> In article <···············@mid.individual.net>,
> > >>>  Pascal Costanza <··@p-cos.net> wrote:
> > >>>
> > >>>>> (Just FYI, the reason I'm interested in understanding this is because 
> > >>>>> I 
> > >>>>> want to make macros do the Right Thing in my lexicon library.)
> > >>>> Then you probably want hygienic macros. Look at Will Clinger's 
> > >>>> "Hygienic 
> > >>>> Macros Through Explicit Renaming" paper for a simple version.
> > >>> Maybe.  I'm thinking there might be a sneakier solution though :-)
> > >> And I think I was right:
> > >>
> > > ? (defmacro foo () (macroexpand 'x))
> > > FOO
> > > ? (foo)
> > > 2
> > > ? x
> > > 2
> > > ? (defun f () (foo))
> > > F
> > > ? (f)
> > > 2
> > > ? (incf x)
> > > 3
> > > ? (f)
> > > 3
> > > ? (let ((x 4)) (f))
> > > ;Compiler warnings :
> > > ;   Unused lexical variable X, in an anonymous lambda form.
> > > 3
> > > ? 
> > 
> > I think you're still wrong:
> > 
> > (flet ((foo () 4))
> >    (f))
> > => probably returns 4 now
> > 
> > If you want referential transparency, you should protect yourself 
> > against any kind of influence from the outside, not only from variables.
> 
> One thing at a time :-)
> 
> rg

Actually, it seems to work properly as it stands:


? (flet ((foo () 4)) (f))
2
? (macrolet ((foo () 5)) (f))
2
? 

rg
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <620sogF209tgtU1@mid.individual.net>
Ron Garret wrote:
> In article <·······························@news.gha.chartermi.net>,
>  Ron Garret <·········@flownet.com> wrote:
> 
>> In article <···············@mid.individual.net>,
>>  Pascal Costanza <··@p-cos.net> wrote:
>>
>>> Ron Garret wrote:
>>>> In article <·······························@news.gha.chartermi.net>,
>>>>  Ron Garret <·········@flownet.com> wrote:
>>>>
>>>>> In article <·······························@news.gha.chartermi.net>,
>>>>>  Ron Garret <·········@flownet.com> wrote:
>>>>>
>>>>>> In article <···············@mid.individual.net>,
>>>>>>  Pascal Costanza <··@p-cos.net> wrote:
>>>>>>
>>>>>>>> (Just FYI, the reason I'm interested in understanding this is because 
>>>>>>>> I 
>>>>>>>> want to make macros do the Right Thing in my lexicon library.)
>>>>>>> Then you probably want hygienic macros. Look at Will Clinger's 
>>>>>>> "Hygienic 
>>>>>>> Macros Through Explicit Renaming" paper for a simple version.
>>>>>> Maybe.  I'm thinking there might be a sneakier solution though :-)
>>>>> And I think I was right:
>>>>>
>>>> ? (defmacro foo () (macroexpand 'x))
>>>> FOO
>>>> ? (foo)
>>>> 2
>>>> ? x
>>>> 2
>>>> ? (defun f () (foo))
>>>> F
>>>> ? (f)
>>>> 2
>>>> ? (incf x)
>>>> 3
>>>> ? (f)
>>>> 3
>>>> ? (let ((x 4)) (f))
>>>> ;Compiler warnings :
>>>> ;   Unused lexical variable X, in an anonymous lambda form.
>>>> 3
>>>> ? 
>>> I think you're still wrong:
>>>
>>> (flet ((foo () 4))
>>>    (f))
>>> => probably returns 4 now
>>>
>>> If you want referential transparency, you should protect yourself 
>>> against any kind of influence from the outside, not only from variables.
>> One thing at a time :-)
>>
>> rg
> 
> Actually, it seems to work properly as it stands:
> 
> 
> ? (flet ((foo () 4)) (f))
> 2
> ? (macrolet ((foo () 5)) (f))
> 2
> ? 

Ouch. :)

Yes, of course. Because you're not using the macro locally anymore. 
That's cheating... ;) [...and you don't need to call macroexpand in foo, 
just return 'x.]


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Ron Garret
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <rNOSPAMon-DC7825.12383919022008@news.gha.chartermi.net>
In article <···············@mid.individual.net>,
 Pascal Costanza <··@p-cos.net> wrote:

> Ron Garret wrote:
> > In article <·······························@news.gha.chartermi.net>,
> >  Ron Garret <·········@flownet.com> wrote:
> > 
> >> In article <···············@mid.individual.net>,
> >>  Pascal Costanza <··@p-cos.net> wrote:
> >>
> >>> Ron Garret wrote:
> >>>> In article <·······························@news.gha.chartermi.net>,
> >>>>  Ron Garret <·········@flownet.com> wrote:
> >>>>
> >>>>> In article <·······························@news.gha.chartermi.net>,
> >>>>>  Ron Garret <·········@flownet.com> wrote:
> >>>>>
> >>>>>> In article <···············@mid.individual.net>,
> >>>>>>  Pascal Costanza <··@p-cos.net> wrote:
> >>>>>>
> >>>>>>>> (Just FYI, the reason I'm interested in understanding this is 
> >>>>>>>> because 
> >>>>>>>> I 
> >>>>>>>> want to make macros do the Right Thing in my lexicon library.)
> >>>>>>> Then you probably want hygienic macros. Look at Will Clinger's 
> >>>>>>> "Hygienic 
> >>>>>>> Macros Through Explicit Renaming" paper for a simple version.
> >>>>>> Maybe.  I'm thinking there might be a sneakier solution though :-)
> >>>>> And I think I was right:
> >>>>>
> >>>> ? (defmacro foo () (macroexpand 'x))
> >>>> FOO
> >>>> ? (foo)
> >>>> 2
> >>>> ? x
> >>>> 2
> >>>> ? (defun f () (foo))
> >>>> F
> >>>> ? (f)
> >>>> 2
> >>>> ? (incf x)
> >>>> 3
> >>>> ? (f)
> >>>> 3
> >>>> ? (let ((x 4)) (f))
> >>>> ;Compiler warnings :
> >>>> ;   Unused lexical variable X, in an anonymous lambda form.
> >>>> 3
> >>>> ? 
> >>> I think you're still wrong:
> >>>
> >>> (flet ((foo () 4))
> >>>    (f))
> >>> => probably returns 4 now
> >>>
> >>> If you want referential transparency, you should protect yourself 
> >>> against any kind of influence from the outside, not only from variables.
> >> One thing at a time :-)
> >>
> >> rg
> > 
> > Actually, it seems to work properly as it stands:
> > 
> > 
> > ? (flet ((foo () 4)) (f))
> > 2
> > ? (macrolet ((foo () 5)) (f))
> > 2
> > ? 
> 
> Ouch. :)
> 
> Yes, of course. Because you're not using the macro locally anymore. 

I don't understand what you mean by that.

> That's cheating... ;) [...and you don't need to call macroexpand in foo, 
> just return 'x.]

No, that doesn't work:

? (foo)
4
? (let ((x 0)) (foo))
0
? 

rg
From: Ron Garret
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <rNOSPAMon-6CD759.12401219022008@news.gha.chartermi.net>
In article <·······························@news.gha.chartermi.net>,
 Ron Garret <·········@flownet.com> wrote:

> In article <···············@mid.individual.net>,
>  Pascal Costanza <··@p-cos.net> wrote:
> 
> > Ron Garret wrote:
> > > In article <·······························@news.gha.chartermi.net>,
> > >  Ron Garret <·········@flownet.com> wrote:
> > > 
> > >> In article <···············@mid.individual.net>,
> > >>  Pascal Costanza <··@p-cos.net> wrote:
> > >>
> > >>> Ron Garret wrote:
> > >>>> In article <·······························@news.gha.chartermi.net>,
> > >>>>  Ron Garret <·········@flownet.com> wrote:
> > >>>>
> > >>>>> In article <·······························@news.gha.chartermi.net>,
> > >>>>>  Ron Garret <·········@flownet.com> wrote:
> > >>>>>
> > >>>>>> In article <···············@mid.individual.net>,
> > >>>>>>  Pascal Costanza <··@p-cos.net> wrote:
> > >>>>>>
> > >>>>>>>> (Just FYI, the reason I'm interested in understanding this is 
> > >>>>>>>> because 
> > >>>>>>>> I 
> > >>>>>>>> want to make macros do the Right Thing in my lexicon library.)
> > >>>>>>> Then you probably want hygienic macros. Look at Will Clinger's 
> > >>>>>>> "Hygienic 
> > >>>>>>> Macros Through Explicit Renaming" paper for a simple version.
> > >>>>>> Maybe.  I'm thinking there might be a sneakier solution though :-)
> > >>>>> And I think I was right:
> > >>>>>
> > >>>> ? (defmacro foo () (macroexpand 'x))
> > >>>> FOO
> > >>>> ? (foo)
> > >>>> 2
> > >>>> ? x
> > >>>> 2
> > >>>> ? (defun f () (foo))
> > >>>> F
> > >>>> ? (f)
> > >>>> 2
> > >>>> ? (incf x)
> > >>>> 3
> > >>>> ? (f)
> > >>>> 3
> > >>>> ? (let ((x 4)) (f))
> > >>>> ;Compiler warnings :
> > >>>> ;   Unused lexical variable X, in an anonymous lambda form.
> > >>>> 3
> > >>>> ? 
> > >>> I think you're still wrong:
> > >>>
> > >>> (flet ((foo () 4))
> > >>>    (f))
> > >>> => probably returns 4 now
> > >>>
> > >>> If you want referential transparency, you should protect yourself 
> > >>> against any kind of influence from the outside, not only from variables.
> > >> One thing at a time :-)
> > >>
> > >> rg
> > > 
> > > Actually, it seems to work properly as it stands:
> > > 
> > > 
> > > ? (flet ((foo () 4)) (f))
> > > 2
> > > ? (macrolet ((foo () 5)) (f))
> > > 2
> > > ? 
> > 
> > Ouch. :)
> > 
> > Yes, of course. Because you're not using the macro locally anymore. 
> 
> I don't understand what you mean by that.
> 
> > That's cheating... ;) [...and you don't need to call macroexpand in foo, 
> > just return 'x.]
> 
> No, that doesn't work:
> 
> ? (foo)
> 4
> ? (let ((x 0)) (foo))
> 0
> ? 
> 
> rg

Whoops, left out some important context:

? (defmacro foo () 'x)
FOO
? (foo)
4
? (let ((x 0)) (foo))
0
? 

By way of contrast:

? (defmacro foo () (macroexpand 'x))
FOO
? (foo)
4
? (let ((x 0)) (foo))
;Compiler warnings :
;   Unused lexical variable X, in an anonymous lambda form.
4
? 

rg
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <620vb7F21idesU1@mid.individual.net>
Ron Garret wrote:
> In article <···············@mid.individual.net>,
>  Pascal Costanza <··@p-cos.net> wrote:
> 
>> Ron Garret wrote:
>>> In article <·······························@news.gha.chartermi.net>,
>>>  Ron Garret <·········@flownet.com> wrote:
>>>
>>>> In article <···············@mid.individual.net>,
>>>>  Pascal Costanza <··@p-cos.net> wrote:
>>>>
>>>>> Ron Garret wrote:
>>>>>> In article <·······························@news.gha.chartermi.net>,
>>>>>>  Ron Garret <·········@flownet.com> wrote:
>>>>>>
>>>>>>> In article <·······························@news.gha.chartermi.net>,
>>>>>>>  Ron Garret <·········@flownet.com> wrote:
>>>>>>>
>>>>>>>> In article <···············@mid.individual.net>,
>>>>>>>>  Pascal Costanza <··@p-cos.net> wrote:
>>>>>>>>
>>>>>>>>>> (Just FYI, the reason I'm interested in understanding this is 
>>>>>>>>>> because 
>>>>>>>>>> I 
>>>>>>>>>> want to make macros do the Right Thing in my lexicon library.)
>>>>>>>>> Then you probably want hygienic macros. Look at Will Clinger's 
>>>>>>>>> "Hygienic 
>>>>>>>>> Macros Through Explicit Renaming" paper for a simple version.
>>>>>>>> Maybe.  I'm thinking there might be a sneakier solution though :-)
>>>>>>> And I think I was right:
>>>>>>>
>>>>>> ? (defmacro foo () (macroexpand 'x))
>>>>>> FOO
>>>>>> ? (foo)
>>>>>> 2
>>>>>> ? x
>>>>>> 2
>>>>>> ? (defun f () (foo))
>>>>>> F
>>>>>> ? (f)
>>>>>> 2
>>>>>> ? (incf x)
>>>>>> 3
>>>>>> ? (f)
>>>>>> 3
>>>>>> ? (let ((x 4)) (f))
>>>>>> ;Compiler warnings :
>>>>>> ;   Unused lexical variable X, in an anonymous lambda form.
>>>>>> 3
>>>>>> ? 
>>>>> I think you're still wrong:
>>>>>
>>>>> (flet ((foo () 4))
>>>>>    (f))
>>>>> => probably returns 4 now
>>>>>
>>>>> If you want referential transparency, you should protect yourself 
>>>>> against any kind of influence from the outside, not only from variables.
>>>> One thing at a time :-)
>>>>
>>>> rg
>>> Actually, it seems to work properly as it stands:
>>>
>>>
>>> ? (flet ((foo () 4)) (f))
>>> 2
>>> ? (macrolet ((foo () 5)) (f))
>>> 2
>>> ? 
>> Ouch. :)
>>
>> Yes, of course. Because you're not using the macro locally anymore. 
> 
> I don't understand what you mean by that.

If you call the function f locally, you don't call the macro foo locally.

>> That's cheating... ;) [...and you don't need to call macroexpand in foo, 
>> just return 'x.]
> 
> No, that doesn't work:
> 
> ? (foo)
> 4
> ? (let ((x 0)) (foo))
> 0
> ? 

Yes, if you call the macro foo locally, things are different again.


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <622pb0F21i4l4U3@mid.individual.net>
Ron Garret wrote:
> In article <···············@mid.individual.net>,
>  Pascal Costanza <··@p-cos.net> wrote:
> 
>> Ron Garret wrote:
>>> In article <·······························@news.gha.chartermi.net>,
>>>  Ron Garret <·········@flownet.com> wrote:
>>>
>>>> In article <···············@mid.individual.net>,
>>>>  Pascal Costanza <··@p-cos.net> wrote:
>>>>
>>>>> Ron Garret wrote:
>>>>>> In article <·······························@news.gha.chartermi.net>,
>>>>>>  Ron Garret <·········@flownet.com> wrote:
>>>>>>
>>>>>>> In article <·······························@news.gha.chartermi.net>,
>>>>>>>  Ron Garret <·········@flownet.com> wrote:
>>>>>>>
>>>>>>>> In article <···············@mid.individual.net>,
>>>>>>>>  Pascal Costanza <··@p-cos.net> wrote:
>>>>>>>>
>>>>>>>>>> (Just FYI, the reason I'm interested in understanding this is 
>>>>>>>>>> because 
>>>>>>>>>> I 
>>>>>>>>>> want to make macros do the Right Thing in my lexicon library.)
>>>>>>>>> Then you probably want hygienic macros. Look at Will Clinger's 
>>>>>>>>> "Hygienic 
>>>>>>>>> Macros Through Explicit Renaming" paper for a simple version.
>>>>>>>> Maybe.  I'm thinking there might be a sneakier solution though :-)
>>>>>>> And I think I was right:
>>>>>>>
>>>>>> ? (defmacro foo () (macroexpand 'x))
>>>>>> FOO
>>>>>> ? (foo)
>>>>>> 2
>>>>>> ? x
>>>>>> 2
>>>>>> ? (defun f () (foo))
>>>>>> F
>>>>>> ? (f)
>>>>>> 2
>>>>>> ? (incf x)
>>>>>> 3
>>>>>> ? (f)
>>>>>> 3
>>>>>> ? (let ((x 4)) (f))
>>>>>> ;Compiler warnings :
>>>>>> ;   Unused lexical variable X, in an anonymous lambda form.
>>>>>> 3
>>>>>> ? 
>>>>> I think you're still wrong:
>>>>>
>>>>> (flet ((foo () 4))
>>>>>    (f))
>>>>> => probably returns 4 now
>>>>>
>>>>> If you want referential transparency, you should protect yourself 
>>>>> against any kind of influence from the outside, not only from variables.
>>>> One thing at a time :-)
>>>>
>>>> rg
>>> Actually, it seems to work properly as it stands:
>>>
>>>
>>> ? (flet ((foo () 4)) (f))
>>> 2
>>> ? (macrolet ((foo () 5)) (f))
>>> 2
>>> ? 
>> Ouch. :)
>>
>> Yes, of course. Because you're not using the macro locally anymore. 
> 
> I don't understand what you mean by that.

(flet ((foo () 4)) (f)) <= you're calling the function f here, not any macro


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <620ve4F21idesU2@mid.individual.net>
Ron Garret wrote:

> Probably need to stick some &environment args in there to really make it 
> work right.

Yes, you're on the right track, but this requires considerably more work 
to make this really reliable. But it can be done...


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Kaz Kylheku
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <10f59ae3-cf16-4d4d-85cc-faeaa125a66b@e10g2000prf.googlegroups.com>
On Feb 19, 10:42 am, Ron Garret <·········@flownet.com> wrote:
> In article <·······························@news.gha.chartermi.net>,
>  Ron Garret <·········@flownet.com> wrote:
>
> > In article <···············@mid.individual.net>,
> >  Pascal Costanza <····@p-cos.net> wrote:
>
> > > > (Just FYI, the reason I'm interested in understanding this is because I
> > > > want to make macros do the Right Thing in my lexicon library.)
>
> > > Then you probably want hygienic macros. Look at Will Clinger's "Hygienic
> > > Macros Through Explicit Renaming" paper for a simple version.
>
> > Maybe.  I'm thinking there might be a sneakier solution though :-)
>
> And I think I was right:
>
> ? (defglobal x 1)
> 1
> ? (macroexpand 'x)
> (SYMBOL-VALUE '#:X)
> T
> ? (defmacro foo () `',x)

This way of referencing the macro's environment in the expansion has
limited power, because the value of X gets interpolated into that
expansion. So the site where the expansion is substituted doesn't
actually have a reference to the original X at ll.

> FOO
> ? (foo)
> 1
> ? (setf x 2)
> 2
> ? (foo)
> 2
> ? (let ((x 3)) (foo))
> ;Compiler warnings :
> ;   Unused lexical variable X, in an anonymous lambda form.
> 2

The relevant test case here is this:

(setf x 2)

(defun what-is-foo ()
  (foo))

(setf x 42)

(what-is-foo)  ->  2

The value of X gets baked into the macroexpansion as a literal
constant. Changing X has no effect. If the replacement form
substituted for (FOO) really contained transparent lexical reference
to X, then (WHAT-IS-FOO) would report the current value of X.

Backquote isn't magic. `',x is just another way of saying (list 'quote
x), and so (defmacro foo () `',x) is like (defmacro foo () (list
'quote x)).  (foo) means ``substitute the current value of X as a
quoted literal here''. If x is 42 then (foo) returns (QUOTE 42).

Sorry, you need a closure to make it work right:

(defmacro foo()
  `(funcall ,(lambda () x)))

Now when you call (FOO) you get the code

 (funcall #<unprintable function object returning x>)

And the problem with this ... drum roll ... that the Common Lisp
specification does not require functions to be externalizeable
objects. This means that you cannot portably stick a function into
Lisp source code and expect that to compile; implementations are not
required to be able to take a closure (code and environment and all)
and stick it into the translated object file.

Scheme doesn't address this kind of petty concern because it has no
model for file compiling, loading or, really, composing a large
program out of little pieces.
From: Jens Axel Soegaard
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <47bb6803$0$15883$edfadb0f@dtext01.news.tele.dk>
Kaz Kylheku wrote:

[nice analysis snipped]

> Scheme doesn't address this kind of petty concern because it has no
> model for file compiling, loading or, really, composing a large
> program out of little pieces.

Where "Scheme" is R5RS Scheme.
In R6RS libraries (aka modules) where introduced.

-- 
Jens Axel S�gaard
From: Jens Axel Soegaard
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <47b88433$0$15898$edfadb0f@dtext01.news.tele.dk>
Pascal Costanza wrote:

> The problem can be relatively easily circumvented in Common Lisp by 
> using the package system and choosing names more carefully. After all, 
> the following actually does what you expect:

> If Common Lisp had a module system instead of a package system, and if 
> Common Lisp were a Lisp-1 instead of a Lisp-2, referential transparency 
> would be a much more pressing issue. [1]
> 
> Nevertheless, hygienic macro systems are strictly more powerful in that 
> regard than defmacro-style macro systems.


I wonder how long it takes the Arcers (?) to realize the problems.

-- 
Jens Axel S�gaard
From: Ron Garret
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <rNOSPAMon-771CF3.12205417022008@news.gha.chartermi.net>
In article <·························@dtext01.news.tele.dk>,
 Jens Axel Soegaard <·······@soegaard.net> wrote:

> Pascal Costanza wrote:
> 
> > The problem can be relatively easily circumvented in Common Lisp by 
> > using the package system and choosing names more carefully. After all, 
> > the following actually does what you expect:
> 
> > If Common Lisp had a module system instead of a package system, and if 
> > Common Lisp were a Lisp-1 instead of a Lisp-2, referential transparency 
> > would be a much more pressing issue. [1]
> > 
> > Nevertheless, hygienic macro systems are strictly more powerful in that 
> > regard than defmacro-style macro systems.
> 
> 
> I wonder how long it takes the Arcers (?) to realize the problems.

They realize the problem (or at least Paul does).  He just doesn't 
believe that it's a problem.

rg
From: Abdulaziz Ghuloum
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fpa5uj$jjk$1@aioe.org>
Ron Garret wrote:

> They realize the problem (or at least Paul does).  He just doesn't 
> believe that it's a problem.

If describing unintended capture as "kind of freaky" does not
qualify as admitting the problem, I don't know what does.

   http://arclanguage.org/item?id=2504
From: Ron Garret
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <rNOSPAMon-6539AD.12521217022008@news.gha.chartermi.net>
In article <············@aioe.org>,
 Abdulaziz Ghuloum <········@cee.ess.indiana.edu> wrote:

> Ron Garret wrote:
> 
> > They realize the problem (or at least Paul does).  He just doesn't 
> > believe that it's a problem.
> 
> If describing unintended capture as "kind of freaky" does not
> qualify as admitting the problem, I don't know what does.
> 
>    http://arclanguage.org/item?id=2504

Like I said, Paul is aware of the problem.  He just thinks it can be 
dealt with informally, through naming conventions or some such thing.

See http://www.paulgraham.com/arcchallenge.html

rg
From: Ken Tilton
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <47b8c515$0$25049$607ed4bc@cv.net>
Abdulaziz Ghuloum wrote:
> Ron Garret wrote:
> 
>> They realize the problem (or at least Paul does).  He just doesn't 
>> believe that it's a problem.
> 
> 
> If describing unintended capture as "kind of freaky" does not
> qualify as admitting the problem, I don't know what does.

Uh, that would be "not choosing it for Arc and then mentioning it (along 
with (is nil '()) -> t) as a deliberate design choice".

In a couple of messages pg has laid down a constraint on whining about 
Arc: only stuff that creates a problem /in practice/ is of interest.

Unhygienic macros, as freaky as they may be, never make a problem in 
practice (except for foot-shooters who skimp on gensyms) and for some 
stupid pet tricks variable capture is the only way to go.

btw, even after all these years Cells scares me, esp. when I sneak them 
into a database such that it runs around updating itself. But I know 
Cells works, so while I may joke about trying to get it past change 
control (and doubt I could anywhere I am not the change control 
committee), that joking should not be construed as a sober engineering 
conviction. As if I am ever sober.

kt

-- 
http://smuglispweeny.blogspot.com/
http://www.theoryyalgebra.com/

"In the morning, hear the Way;
  in the evening, die content!"
                     -- Confucius
From: Abdulaziz Ghuloum
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fpaij6$q3l$1@aioe.org>
Ken Tilton wrote:

> In a couple of messages pg has laid down a constraint on whining about 
> Arc: only stuff that creates a problem /in practice/ is of interest.

NOTHING creates a problem in practice.  Dynamic scope: not a problem,
just look at all the elisp code out there.  Nonhygienic macros: not a
problem, just gensym and go.  Lack of module system: follow a naming
convention.  No static type system: we never have type errors around
here.  And so on and so on.  People always find workarounds.  (often
times, these are excuses, not solutions, since there is no problem
to begin with.)

Remember that Fortran has no problems in practice if one is willing
to dismiss every innovation in programming languages over the last
N years as a theoretical solution to a nonexistent problem.
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <61s4keF20oi52U1@mid.individual.net>
Abdulaziz Ghuloum wrote:
> Ken Tilton wrote:
> 
>> In a couple of messages pg has laid down a constraint on whining about 
>> Arc: only stuff that creates a problem /in practice/ is of interest.
> 
> NOTHING creates a problem in practice.  Dynamic scope: not a problem,
> just look at all the elisp code out there.  Nonhygienic macros: not a
> problem, just gensym and go.  Lack of module system: follow a naming
> convention.  No static type system: we never have type errors around
> here.  And so on and so on.  People always find workarounds.  (often
> times, these are excuses, not solutions, since there is no problem
> to begin with.)

It's not about workarounds, it's about trade offs. Hygienic macro 
systems screw up the idea that code is made up of conses, symbols and 
atoms, and destroys the conceptual simplicity of that model. Lisp-style 
macro systems are nice in that regard, because I can use _any_ library 
that operates on conses on program representations as well, because 
conses _are_ also program representations in Lisp. I don't need to think 
of programs being something substantially different from my other data 
structures that I use every day.

Some people find that conceptual simplicity more compelling than fixing 
problems that don't really occur in practice. (Note we're talking about 
Common Lisp here, in which problems with referential transparency indeed 
hardly ever occur. That seems to be different in Scheme.)

You have similar trade offs for the other examples you mention as well.

> Remember that Fortran has no problems in practice if one is willing
> to dismiss every innovation in programming languages over the last
> N years as a theoretical solution to a nonexistent problem.

Fortran is not a programmable programming language. ;)


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <331466c7-4c65-46e2-ab9b-bee2a8f44343@34g2000hsz.googlegroups.com>
On Feb 17, 8:17 pm, Pascal Costanza <····@p-cos.net> wrote:

> It's not about workarounds, it's about trade offs. Hygienic macro
> systems screw up the idea that code is made up of conses, symbols and
> atoms,

Not necessarily.  Various existing hygienic macro systems represent
code
as conses, atoms and identifiers.  Identifiers can furthermore
perfectly
well be represented as symbols in hygienic macro systems.  They were
in
fact so represented in the original KFFD hygiene paper example
implementation, and are still represented as symbols in, I believe,
one
or two implementations of explicit renaming.  If identifiers are
currently
represented as an orthogonal data type in various implementations,
that is
more a matter of convenience than any fundamental requirement.

Andre
From: Raffael Cavallaro
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <2008021801311450073-raffaelcavallaro@pasdespamsilvousplaitmaccom>
Have to say, it seems nearly perverse to me to build a new lisp dialect 
using mzscheme and *not* take advantage of the ability to have 
back-quote based macros with both hygiene by default and intentional 
capture when wanted. I could understand if one were using common lisp 
as a base and didn't want to make the effort, but with mzscheme (and 
several other scheme implementations) it's just sitting there waiting 
to be used.

Not that this is the only thing that seems puzzling about the choices 
made. Also disappointing is the near complete focus on syntax to the 
exclusion of semantics. What's the semantics of unicode? Dunno. What's 
the semantics of threads under SMP? Dunno. But lets make sure all the 
function names are four characters or fewer!
From: Ken Tilton
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <47b9410a$0$25061$607ed4bc@cv.net>
Raffael Cavallaro wrote:
> Have to say, it seems nearly perverse to me to build a new lisp dialect 
> using mzscheme and *not* take advantage of the ability to have 
> back-quote based macros with both hygiene by default and intentional 
> capture when wanted. I could understand if one were using common lisp as 
> a base and didn't want to make the effort, but with mzscheme (and 
> several other scheme implementations) it's just sitting there waiting to 
> be used.
> 
> Not that this is the only thing that seems puzzling about the choices 
> made. Also disappointing is the near complete focus on syntax to the 
> exclusion of semantics. What's the semantics of unicode? Dunno. What's 
> the semantics of threads under SMP? Dunno. But lets make sure all the 
> function names are four characters or fewer!
> 

Forest. Trees. Please stand back.

It's getting crazy over there, someone just suggested significant 
whitespace, and what with : and , and ! and infix math the parenthesis 
is a downright threatened species, but the wild and crazy thing is that 
pg is accepting ideas left and right and we have this communal thing 
going on, who knows maybe they will accept Cells and kick my installed 
base above a dozen.

I wouldn't be missing this for the world. My rough take is that the mad 
dash for brevity and fewer parens will produce a horrid language and 
distract everyone from the Unbearable Beauty of () and hence really of 
Lisp, but it is going to be a fun ride.

kenny

-- 
http://smuglispweeny.blogspot.com/
http://www.theoryyalgebra.com/

"In the morning, hear the Way;
  in the evening, die content!"
                     -- Confucius
From: Damien Kick
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <13rv0605k6pnrc2@corp.supernews.com>
Ken Tilton wrote:
> 
> 
> Raffael Cavallaro wrote:
>> Have to say, it seems nearly perverse to me to build a new lisp 
>> dialect using mzscheme and *not* take advantage [...]
> 
> Forest. Trees. Please stand back.

Stand back a little further.  Keep going.  Head towards that cliff over 
there.  You're not quite there yet.  Can you see it yet?  A little further.

> [...] we have this communal thing going on, [...]

Said one lemming to another.

> I wouldn't be missing this for the world. My rough take is that the mad 
> dash for brevity and fewer parens will produce a horrid language and 
> distract everyone from the Unbearable Beauty of () and hence really of 
> Lisp, but it is going to be a fun ride.

What does it sounds like, the wind in the willows?  I wonder if any of 
this will involve Kenny disguised as a washerwoman.
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <6264lhF1vjcg0U1@mid.individual.net>
············@yahoo.com wrote:
> On Feb 17, 8:17 pm, Pascal Costanza <····@p-cos.net> wrote:
> 
>> It's not about workarounds, it's about trade offs. Hygienic macro
>> systems screw up the idea that code is made up of conses, symbols and
>> atoms,
> 
> Not necessarily. Various existing hygienic macro systems represent 
> code as conses, atoms and identifiers. Identifiers can furthermore 
> perfectly well be represented as symbols in hygienic macro systems.
> They were in fact so represented in the original KFFD hygiene paper
> example implementation, and are still represented as symbols in, I
> believe, one or two implementations of explicit renaming. If
> identifiers are currently represented as an orthogonal data type in
> various implementations, that is more a matter of convenience than
> any fundamental requirement.

Hm, sounds interesting, but I'm not yet convinced. How do you pass parts 
of the macroexpansion job to helper functions (which may be in separate 
lexical environments) and still ensure that identifiers refer to the 
"correct" bindings in such systems?

Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <a9fdf55b-e73f-4bcc-a152-594f6ef107e4@p25g2000hsf.googlegroups.com>
On Feb 21, 3:18 pm, Pascal Costanza <····@p-cos.net> wrote:
> ············@yahoo.com wrote:
> > On Feb 17, 8:17 pm, Pascal Costanza <····@p-cos.net> wrote:
>
> >> It's not about workarounds, it's about trade offs. Hygienic macro
> >> systems screw up the idea that code is made up of conses, symbols and
> >> atoms,
>
> > Not necessarily. Various existing hygienic macro systems represent
> > code as conses, atoms and identifiers. Identifiers can furthermore
> > perfectly well be represented as symbols in hygienic macro systems.
> > They were in fact so represented in the original KFFD hygiene paper
> > example implementation, and are still represented as symbols in, I
> > believe, one or two implementations of explicit renaming. If
> > identifiers are currently represented as an orthogonal data type in
> > various implementations, that is more a matter of convenience than
> > any fundamental requirement.
>
> Hm, sounds interesting, but I'm not yet convinced. How do you pass parts
> of the macroexpansion job to helper functions (which may be in separate
> lexical environments) and still ensure that identifiers refer to the
> "correct" bindings in such systems?

In explicit renaming you can typically only refer to the lexical
environment in which the main macro occurred.  The environment is
implicit in the renaming function that gets passed to the main macro,
which you would then pass along to the helper function.  Thus, the
helper function cannot refer to its own lexical environment if it
is different from the main macro's.

It is possible to extend explicit renaming with additional syntax
that would create a renaming function corresponding to any local
lexical environment on the fly.  Nobody has bothered doing this
as far as I know.

In the original KFFD paper there were no local macros (macrolet or
let[rec]-syntax) or modules.  In that case all macro-introduced
identifiers that were not locally bound would refer
to the the unique toplevel environment, which made things
very simple.  The algorithm did not even have to bother
with environment data structures at all.

Andre
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <626ci7F21pd3qU1@mid.individual.net>
············@yahoo.com wrote:
> On Feb 21, 3:18 pm, Pascal Costanza <····@p-cos.net> wrote:
>> ············@yahoo.com wrote:
>>> On Feb 17, 8:17 pm, Pascal Costanza <····@p-cos.net> wrote:
>>>> It's not about workarounds, it's about trade offs. Hygienic macro
>>>> systems screw up the idea that code is made up of conses, symbols and
>>>> atoms,
>>> Not necessarily. Various existing hygienic macro systems represent
>>> code as conses, atoms and identifiers. Identifiers can furthermore
>>> perfectly well be represented as symbols in hygienic macro systems.
>>> They were in fact so represented in the original KFFD hygiene paper
>>> example implementation, and are still represented as symbols in, I
>>> believe, one or two implementations of explicit renaming. If
>>> identifiers are currently represented as an orthogonal data type in
>>> various implementations, that is more a matter of convenience than
>>> any fundamental requirement.
>> Hm, sounds interesting, but I'm not yet convinced. How do you pass parts
>> of the macroexpansion job to helper functions (which may be in separate
>> lexical environments) and still ensure that identifiers refer to the
>> "correct" bindings in such systems?
> 
> In explicit renaming you can typically only refer to the lexical
> environment in which the main macro occurred.  The environment is
> implicit in the renaming function that gets passed to the main macro,
> which you would then pass along to the helper function.  Thus, the
> helper function cannot refer to its own lexical environment if it
> is different from the main macro's.

Well, this starts to sound like the kind of "screwing up" I had in mind.

> It is possible to extend explicit renaming with additional syntax
> that would create a renaming function corresponding to any local
> lexical environment on the fly.  Nobody has bothered doing this
> as far as I know.

And this starts to sound like hand-waving.

That's why I still prefer Common Lisp's macro systems over other ones 
(including hygienic and non-hygienic macro systems in Scheme). I know 
how to avoid hygiene issues, including possible issues with referential 
transparency, in Common Lisp. It's not rocket science. Plus I have total 
control over how to perform macroexpansion, I'm not restricted by any 
limitations. Plus I have symbol macros and environment objects, which 
give me a lot of additional power.

Simple macros may be simpler to write with syntax-rules & co., but the 
complex ones still seem much simpler with Common Lisp's macro system.


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <456a3c7f-0800-477d-a23b-4e49df401958@m23g2000hsc.googlegroups.com>
On Feb 21, 5:33 pm, Pascal Costanza <····@p-cos.net> wrote:
> ············@yahoo.com wrote:
>
> > In explicit renaming you can typically only refer to the lexical
> > environment in which the main macro occurred.  The environment is
> > implicit in the renaming function that gets passed to the main macro,
> > which you would then pass along to the helper function.  Thus, the
> > helper function cannot refer to its own lexical environment if it
> > is different from the main macro's.
>
> Well, this starts to sound like the kind of "screwing up" I had in mind.
>
> > It is possible to extend explicit renaming with additional syntax
> > that would create a renaming function corresponding to any local
> > lexical environment on the fly.  Nobody has bothered doing this
> > as far as I know.
>
> And this starts to sound like hand-waving.

I should also mention that R6RS macros get all of these things
right.  As has been said before, at least one implementation of them
represents code as ordinary lists.  Although that implementation
does not represent identifiers as symbols, it could have easily
done so if there were any advantage in doing so.

> Simple macros may be simpler to write with syntax-rules & co., but the
> complex ones still seem much simpler with Common Lisp's macro system.

Given this implementation, most complex Lisp macros can be trivially
transformed into an equivalent Scheme macro.  The Scheme macro will
in many cases be a little shorter due to the fact that calls to gensym
can be left out, but otherwise will look almost identical to the
original.
I find it very hard to believe that the Lisp version will seem
simpler.

Andre
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <6283stF22c29qU1@mid.individual.net>
············@yahoo.com wrote:
> On Feb 21, 5:33 pm, Pascal Costanza <····@p-cos.net> wrote:
>> ············@yahoo.com wrote:
>>
>>> In explicit renaming you can typically only refer to the lexical
>>> environment in which the main macro occurred.  The environment is
>>> implicit in the renaming function that gets passed to the main macro,
>>> which you would then pass along to the helper function.  Thus, the
>>> helper function cannot refer to its own lexical environment if it
>>> is different from the main macro's.
>> Well, this starts to sound like the kind of "screwing up" I had in mind.
>>
>>> It is possible to extend explicit renaming with additional syntax
>>> that would create a renaming function corresponding to any local
>>> lexical environment on the fly.  Nobody has bothered doing this
>>> as far as I know.
>> And this starts to sound like hand-waving.
> 
> I should also mention that R6RS macros get all of these things
> right.  As has been said before, at least one implementation of them
> represents code as ordinary lists.  Although that implementation
> does not represent identifiers as symbols, it could have easily
> done so if there were any advantage in doing so.

Which implementation is that? I'd like to try it...


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <8c2bbdea-eb75-421f-98b5-c003ab30d6af@34g2000hsz.googlegroups.com>
On Feb 22, 9:18 am, Pascal Costanza <····@p-cos.net> wrote:
> ············@yahoo.com wrote:
>
> > I should also mention that R6RS macros get all of these things
> > right.  As has been said before, at least one implementation of them
> > represents code as ordinary lists.  Although that implementation
> > does not represent identifiers as symbols, it could have easily
> > done so if there were any advantage in doing so.
>
> Which implementation is that? I'd like to try it...

Larceny.

Andre
From: Slom
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <934b7dbe-0371-413b-b3dd-c4b52e8749ee@n58g2000hsf.googlegroups.com>
On Feb 21, 11:33 pm, Pascal Costanza <····@p-cos.net> wrote:
>
> Well, this starts to sound like the kind of "screwing up" I had in mind.
>
> > It is possible to extend explicit renaming with additional syntax
> > that would create a renaming function corresponding to any local
> > lexical environment on the fly.  Nobody has bothered doing this
> > as far as I know.
>
> And this starts to sound like hand-waving.
>
> That's why I still prefer Common Lisp's macro systems over other ones
> (including hygienic and non-hygienic macro systems in Scheme). I know
> how to avoid hygiene issues, including possible issues with referential
> transparency, in Common Lisp. It's not rocket science. Plus I have total
> control over how to perform macroexpansion, I'm not restricted by any
> limitations. Plus I have symbol macros and environment objects, which
> give me a lot of additional power.

no this *does* sound like hand-waving ....

> Simple macros may be simpler to write with syntax-rules & co., but the
> complex ones still seem much simpler with Common Lisp's macro system.

would you like to share some of your "complex ones", otherwise this
will *stay*
handwaving for the time being. Maybe also some examples were you tried
(and failed)
to implement your complex macros in syntax-case.

Regards,

Christian
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <62840aF22c29qU2@mid.individual.net>
Slom wrote:
> On Feb 21, 11:33 pm, Pascal Costanza <····@p-cos.net> wrote:
>> Well, this starts to sound like the kind of "screwing up" I had in mind.
>>
>>> It is possible to extend explicit renaming with additional syntax
>>> that would create a renaming function corresponding to any local
>>> lexical environment on the fly.  Nobody has bothered doing this
>>> as far as I know.
>> And this starts to sound like hand-waving.
>>
>> That's why I still prefer Common Lisp's macro systems over other ones
>> (including hygienic and non-hygienic macro systems in Scheme). I know
>> how to avoid hygiene issues, including possible issues with referential
>> transparency, in Common Lisp. It's not rocket science. Plus I have total
>> control over how to perform macroexpansion, I'm not restricted by any
>> limitations. Plus I have symbol macros and environment objects, which
>> give me a lot of additional power.
> 
> no this *does* sound like hand-waving ....
> 
>> Simple macros may be simpler to write with syntax-rules & co., but the
>> complex ones still seem much simpler with Common Lisp's macro system.
> 
> would you like to share some of your "complex ones", otherwise this 
> will *stay* handwaving for the time being. Maybe also some examples
> were you tried (and failed) to implement your complex macros in
> syntax-case.

I'd like to see a syntax-case (or other of the hygienic macro systems) 
version of the kind of macros discussed at 
http://www.lispworks.com/documentation/HyperSpec/Issues/iss066_w.htm


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Slom
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <7d857f94-d6cc-44ef-aed9-6655af022b60@n75g2000hsh.googlegroups.com>
On Feb 22, 3:19 pm, Pascal Costanza <····@p-cos.net> wrote:
> > would you like to share some of your "complex ones", otherwise this
> > will *stay* handwaving for the time being. Maybe also some examples
> > were you tried (and failed) to implement your complex macros in
> > syntax-case.
>
> I'd like to see a syntax-case (or other of the hygienic macro systems)
> version of the kind of macros discussed athttp://www.lispworks.com/documentation/HyperSpec/Issues/iss066_w.htm

that whole document is an argument *for* proper hygiene and phase-
separation ... got more?

(define-syntax typed-var
  (syntax-rules ()
    ((_ var) var)))

(define-syntax the
  (syntax-rules ()
    ((_ ?type ?var) ?var)))

(define-syntax local-declare-types
  (lambda (x)
    (syntax-case x ()
      ((?kw ((?var ?type) ...) . ?forms)
       (let ((%%typed-var (datum->syntax-object #'?kw 'typed-var)))
         #`(let-syntax
               ((#,%%typed-var (syntax-rules (?var ...)
                               ((_ ?var) (the ?type ?var))
                               ...
                               ((_ else) (typed-var else)))))
             . ?forms))))))

(define (f x y)
  (local-declare-types ((x fixnum) (y float))
    (+ (typed-var x) (typed-var y))))
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <97ff5319-7b07-48f3-a91f-238291ffab45@d4g2000prg.googlegroups.com>
On Feb 22, 11:15 am, Slom <·········@gmx.de> wrote:
>
> (define-syntax typed-var
>   (syntax-rules ()
>     ((_ var) var)))
>
> (define-syntax the
>   (syntax-rules ()
>     ((_ ?type ?var) ?var)))
>
> (define-syntax local-declare-types
>   (lambda (x)
>     (syntax-case x ()
>       ((?kw ((?var ?type) ...) . ?forms)
>        (let ((%%typed-var (datum->syntax-object #'?kw 'typed-var)))
>          #`(let-syntax
>                ((#,%%typed-var (syntax-rules (?var ...)
>                                ((_ ?var) (the ?type ?var))
>                                ...
>                                ((_ else) (typed-var else)))))
>              . ?forms))))))
>
> (define (f x y)
>   (local-declare-types ((x fixnum) (y float))
>     (+ (typed-var x) (typed-var y))))

Unfortunately this will not work for nested uses of local-declare-
types.
For example, defining:

(define-syntax the
  (syntax-rules ()
    ((_ ?type ?var) (if (?type ?var) ?var (error "Type error" '?
var)))))

and then

(define (f x y)
  (local-declare-types ((x integer?) (y integer?))
    (let ((z 3))
      (local-declare-types ((z integer?))
         (+ (typed-var x) (typed-var y) (typed-var z))))))

(f 1 1.1) ==> 5.1

whereas an error should have been raised.  The solution that I posted
that uses the expand-time registry will work correctly in this case.

Andre
From: Slom
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <b8c569b6-d49e-44eb-9897-2e32758a85ac@41g2000hsc.googlegroups.com>
On Feb 22, 6:12 pm, ············@yahoo.com wrote:
> On Feb 22, 11:15 am, Slom <·········@gmx.de> wrote:
>
>
>
>
>
> > (define-syntax typed-var
> >   (syntax-rules ()
> >     ((_ var) var)))
>
> > (define-syntax the
> >   (syntax-rules ()
> >     ((_ ?type ?var) ?var)))
>
> > (define-syntax local-declare-types
> >   (lambda (x)
> >     (syntax-case x ()
> >       ((?kw ((?var ?type) ...) . ?forms)
> >        (let ((%%typed-var (datum->syntax-object #'?kw 'typed-var)))
> >          #`(let-syntax
> >                ((#,%%typed-var (syntax-rules (?var ...)
> >                                ((_ ?var) (the ?type ?var))
> >                                ...
> >                                ((_ else) (typed-var else)))))
> >              . ?forms))))))
>
> > (define (f x y)
> >   (local-declare-types ((x fixnum) (y float))
> >     (+ (typed-var x) (typed-var y))))
>
> Unfortunately this will not work for nested uses of local-declare-
> types.
> For example, defining:
>
> (define-syntax the
>   (syntax-rules ()
>     ((_ ?type ?var) (if (?type ?var) ?var (error "Type error" '?
> var)))))
>
> and then
>
> (define (f x y)
>   (local-declare-types ((x integer?) (y integer?))
>     (let ((z 3))
>       (local-declare-types ((z integer?))
>          (+ (typed-var x) (typed-var y) (typed-var z))))))
>
> (f 1 1.1) ==> 5.1
>
> whereas an error should have been raised.  The solution that I posted
> that uses the expand-time registry will work correctly in this case.
>
> Andre


Yep, I noticed that the moment i presses "Send" ... well some seconds
after ;)
The way to fix this would be to rebind local-declare-types too. I
tried but the following doesn't work, and don't know why :(

(define-syntax local-declare-types-aux
  (lambda (x)
    (syntax-case x ()
      ((local-declare-types-aux ?tpl-id ?outer-typed-var ((?var ?
type) ...) . ?forms)
       (let ((inner-typed-var           (datum->syntax-object #'?tpl-
id 'typed-var))
             (inner-local-declare-types (datum->syntax-object #'?tpl-
id 'local-declare-types)))
         #`(let-syntax
               ((#,inner-typed-var
                 (syntax-rules (?var ...)
                   ((_ ?var) (the ?type ?var))
                   ...
                   ((_ else) (?outer-typed-var else))))
                (#,inner-local-declare-types
                 (lambda (x)
                   (syntax-case x ()
                     ((?kw . ?rest)
                      #'(local-declare-types-aux ?kw #,inner-typed-
var . ?rest))))))
             . ?forms))))))

(define-syntax local-declare-types
  (lambda (x)
    (syntax-case x ()
      ((?kw ((?var ?type) ...) . ?forms)
       #'(local-declare-types-aux ?kw typed-var ((?var ?type) ...) . ?
forms)))))

(define-syntax typed-var
  (syntax-rules ()
    ((_ var) var)))

(define-syntax the
  (syntax-rules ()
    ((_ ?type ?var) (list '?type ?var))))
From: Slom
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <52b9ab3e-10c6-41cf-b7f8-5470935b339e@m23g2000hsc.googlegroups.com>
On Feb 22, 6:24 pm, Slom <·········@gmx.de> wrote:
> Yep, I noticed that the moment i presses "Send" ... well some seconds
> after ;)
> The way to fix this would be to rebind local-declare-types too. I
> tried but the following doesn't work, and don't know why :(

Heh that should be letrec-syntax then ... now can CL compete with
this?

(define-syntax local-declare-types-aux
  (lambda (x)
    (syntax-case x ()
      ((local-declare-types-aux ?tpl-id ?outer-typed-var ((?var ?
type) ...) . ?forms)
       (let ((inner-typed-var           (datum->syntax-object #'?tpl-
id 'typed-var))
             (inner-local-declare-types (datum->syntax-object #'?tpl-
id 'local-declare-types)))
         #`(letrec-syntax
               ((#,inner-typed-var
                 (syntax-rules (?var ...)
                   ((_ ?var) (the ?type ?var))
                   ...
                   ((_ else) (?outer-typed-var else))))
                (#,inner-local-declare-types
                 (lambda (x)
                   (syntax-case x ()
                     ((?kw . ?rest)
                      #'(local-declare-types-aux ?kw #,inner-typed-
var . ?rest))))))
             . ?forms))))))

(define-syntax local-declare-types
  (lambda (x)
    (syntax-case x ()
      ((?kw ((?var ?type) ...) . ?forms)
       #'(local-declare-types-aux ?kw typed-var ((?var ?type) ...) . ?
forms)))))

(define-syntax typed-var
  (syntax-rules ()
    ((_ var) var)))

(define-syntax the
  (syntax-rules ()
    ((_ ?type ?var) (list '?type ?var))))

(define a 123)

(define (f b c)
  (local-declare-types ((b symbol) (c string))
    (let ((d 123) (b #\x))
      (local-declare-types ((d integer))
        (list (typed-var a)
              (typed-var b)
              (typed-var c)
              (typed-var d))))))

(f 'foo "bar") ;; => (123 #\x (string "bar") (integer 123)), note the
second element !!!
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <62ad2lF1v5konU2@mid.individual.net>
Slom wrote:
> On Feb 22, 6:24 pm, Slom <·········@gmx.de> wrote:
>> Yep, I noticed that the moment i presses "Send" ... well some seconds
>> after ;)
>> The way to fix this would be to rebind local-declare-types too. I
>> tried but the following doesn't work, and don't know why :(
> 
> Heh that should be letrec-syntax then ... now can CL compete with
> this?

With this _mess_ you mean?

Pascal

> 
> (define-syntax local-declare-types-aux
>   (lambda (x)
>     (syntax-case x ()
>       ((local-declare-types-aux ?tpl-id ?outer-typed-var ((?var ?
> type) ...) . ?forms)
>        (let ((inner-typed-var           (datum->syntax-object #'?tpl-
> id 'typed-var))
>              (inner-local-declare-types (datum->syntax-object #'?tpl-
> id 'local-declare-types)))
>          #`(letrec-syntax
>                ((#,inner-typed-var
>                  (syntax-rules (?var ...)
>                    ((_ ?var) (the ?type ?var))
>                    ...
>                    ((_ else) (?outer-typed-var else))))
>                 (#,inner-local-declare-types
>                  (lambda (x)
>                    (syntax-case x ()
>                      ((?kw . ?rest)
>                       #'(local-declare-types-aux ?kw #,inner-typed-
> var . ?rest))))))
>              . ?forms))))))
> 
> (define-syntax local-declare-types
>   (lambda (x)
>     (syntax-case x ()
>       ((?kw ((?var ?type) ...) . ?forms)
>        #'(local-declare-types-aux ?kw typed-var ((?var ?type) ...) . ?
> forms)))))
> 
> (define-syntax typed-var
>   (syntax-rules ()
>     ((_ var) var)))
> 
> (define-syntax the
>   (syntax-rules ()
>     ((_ ?type ?var) (list '?type ?var))))
> 
> (define a 123)
> 
> (define (f b c)
>   (local-declare-types ((b symbol) (c string))
>     (let ((d 123) (b #\x))
>       (local-declare-types ((d integer))
>         (list (typed-var a)
>               (typed-var b)
>               (typed-var c)
>               (typed-var d))))))
> 
> (f 'foo "bar") ;; => (123 #\x (string "bar") (integer 123)), note the
> second element !!!


-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <e10277d9-da47-483d-b206-3000a3b9a154@k2g2000hse.googlegroups.com>
On Feb 22, 12:24 pm, Slom <·········@gmx.de> wrote:

> The way to fix this would be to rebind local-declare-types too. I
> tried but the following doesn't work, and don't know why :(

...which will probably be held against Scheme (never mind
that the CL alternative solutions are also quite complex).

The macro might be fixable, but I would not spend too much
timeon trying to fix it.  The problem is that breaking
hygiene using datum->syntax in anger often has Consequences.
For example, a solution along these lines would not allow
a user to define his own macro

  (define-syntax my-typed-var
    (syntax-rules ()
      ((_ x) (typed-var x))))

to use in place of typed-var.

The registry solution is simple, maintains hygiene and does
not suffer from this kind of problem.

Andre
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <62ad3oF1v5konU3@mid.individual.net>
············@yahoo.com wrote:
> On Feb 22, 12:24 pm, Slom <·········@gmx.de> wrote:
> 
>> The way to fix this would be to rebind local-declare-types too. I
>> tried but the following doesn't work, and don't know why :(
> 
> ...which will probably be held against Scheme (never mind
> that the CL alternative solutions are also quite complex).

Where do you see complexity in the CL solutions?


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <714170a3-d9fd-4726-aee9-2ed55e615298@q33g2000hsh.googlegroups.com>
On Feb 23, 6:07 am, Pascal Costanza <····@p-cos.net> wrote:
>
> Where do you see complexity in the CL solutions?
>

From the page:

  http://www.lispworks.com/documentation/HyperSpec/Issues/iss066_w.htm

1) "Issue /COMPILER-LET-CONFUSION/ Writeup"
2) "Some people find the COMPILER-LET idiom more understandable
   (/assuming that it can be made to work consistently in compiled
   and interpreted code/), ...
3) "Is it possible to implement COMPILER-LET in a usefully consistent
   way in all implementations?"
4) "Code currently depending on this feature is either non-existent
   or already not portable (due to wide variation in implementation
   strategy for COMPILER-LET)."
5) "Some implementations have implemented the description in CLtL.
   Users of those implementations (quite reasonably) /can't figure/
   how to use COMPILER-LET and so don't use it much."
6) "Some implementations whose interpreters include a preprocessor
    to expand all macros have already implemented something similar
    to proposal COMPILER-LET-CONFUSION:REPAIR. Users of such
    implementations probably use COMPILER-LET somewhat more often
    since it has an intelligible behavior, but their code is not
    portable /since it relies on behaviors which are either contrary
    to or not guaranteed by CLtL./"
7) "Just as rewriting a LET using FLET might obscure the simplicity
    of your intent, so too rewriting COMPILER-LET using MACROLET
    might obscure your intent."
8) "they'd think of how to use MACROLET in the first place to solve
    their problems. This is what people who now use implementations
    with /broken/ COMPILER-LETs already do."
9) The macrolet and symbol-macrolet solutions are much less
   straightforward than the non-portable compiler-let one.

Andre
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <62atkrF22dbk8U1@mid.individual.net>
············@yahoo.com wrote:
> On Feb 23, 6:07 am, Pascal Costanza <····@p-cos.net> wrote:
>> Where do you see complexity in the CL solutions?
>>
> 
> From the page:
> 
>   http://www.lispworks.com/documentation/HyperSpec/Issues/iss066_w.htm
> 
> 1) "Issue /COMPILER-LET-CONFUSION/ Writeup"

COMPILER-LET is not a viable solution in Common Lisp, simply because it 
doesn't exist in Common Lisp. The document is about the confusion that 
COMPILER-LET would create, not the confusion that other, presumably 
better solutions would create.

> 7) "Just as rewriting a LET using FLET might obscure the simplicity
>     of your intent, so too rewriting COMPILER-LET using MACROLET
>     might obscure your intent."
> 8) "they'd think of how to use MACROLET in the first place to solve
>     their problems. This is what people who now use implementations
>     with /broken/ COMPILER-LETs already do."
> 9) The macrolet and symbol-macrolet solutions are much less
>    straightforward than the non-portable compiler-let one.

You should quote everything that is related to the statement:

"Opinion is divided as to which is more understandable.  Some people 
find the COMPILER-LET idiom more understandable (assuming that it can be 
made to work consistently in compiled and interpreted code), while 
others find it just as natural to use MACROLET or SYMBOL-MACROLET."

You quote one of the opinions. Another opinion from the same page is this:

"If COMPILER-LET were not part of the language, people wouldn't think in 
terms of rewriting COMPILER-LETs as MACROLETs; instead, they'd think of 
how to use MACROLET in the first place to solve their problems.  This is 
what people who now use implementations with broken COMPILER-LETs 
already do.  Since MACROLET is now used much more frequently than 
COMPILER-LET, that argues that people are much more familiar with 
MACROLET idioms than COMPILER-LET idioms."

The question whether a solution using COMPILER-LET is complex or not is 
pretty academic: A consistent specification for COMPILER-LET never 
existed, and it's unclear whether an attempt to repair it would have 
been successful.

There are two alternative solutions on the same page using macrolet and 
symbol-macrolet, which actually work in Common Lisp and are not hard to 
understand once you grok environment objects and how they interact with 
macroexpand. As I said elsewhere, they basically give you a way to do 
macroprogramming using expansion-passing style, which is similar in 
complexity to continuation-passing, environment-passing or other kinds 
of xyz-passing style. Especially Schemers should feel comfortable with 
such styles.

The two working solutions are about a dozen lines of straightforward 
code each. The solutions (?) using current hygienic macro systems for 
Scheme presented in this thread seem more complex than that. (Maybe even 
considerably more complex, although that probably depends on which macro 
system you're more used to. But that argument cuts both ways.)


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <0d35b017-5b4b-4d2c-9aea-448df085edb3@v3g2000hsc.googlegroups.com>
On Feb 23, 10:49 am, Pascal Costanza <····@p-cos.net> wrote:

> There are two alternative solutions on the same page using macrolet and
> symbol-macrolet, which actually work in Common Lisp and are not hard to
> understand once you grok environment objects and how they interact with
> macroexpand.

I do not find the solution using macroexpand and eval remotely
simple.

> The two working solutions are about a dozen lines of straightforward
> code each.
> The solutions (?) using current hygienic macro systems for
> Scheme presented in this thread seem more complex than that.

Slom's solution is almost a literal translation to Scheme of the
macrolet example, so the apparent complexity is probably
subjective.  It would have been comparable in length if he
had used ASSP instead of a pattern matching style for the lookup.
Apart from that, I find his solution a bit simpler that the Lisp
one, in that no eval-when annotations are needed for the thing
to work, but the same could probably have been done in Lisp by
making local-type-declare-aux a macro.

However, while it is true that his macro breaks hygiene a little,
the Lisp macrolet example breaks hygiene a lot, and so to be fair
you should really add to the Lisp example the package manipulation
stuff needed to make it as reliable as the Scheme example, along
the lines of your earlier message.  You should also add, to be fair,
code to the macrolet example to check that the syntax of the
declarations list is correct and to raise a readable /syntax/
error if not, as the Scheme version will do automatically.

None of the other solutions remotely approach, IMO, the elegance
and conciseness of Aziz'z solution.

Andre
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <62b65pF22f8l6U1@mid.individual.net>
············@yahoo.com wrote:
> On Feb 23, 10:49 am, Pascal Costanza <····@p-cos.net> wrote:
> 
>> There are two alternative solutions on the same page using macrolet and
>> symbol-macrolet, which actually work in Common Lisp and are not hard to
>> understand once you grok environment objects and how they interact with
>> macroexpand.
> 
> I do not find the solution using macroexpand and eval remotely
> simple.

I do. (The eval is actually not necessary, btw. You could just leave out 
the quote in the symbol-macrolet form and use macroexpand directly on 
the symbol macro. I guess the example was written at a time when 
define-symbol-macro was not part of ANSI Common Lisp yet. With 
define-symbol-macro, the eval workaround is not necessary anymore.)

>> The two working solutions are about a dozen lines of straightforward
>> code each.
>> The solutions (?) using current hygienic macro systems for
>> Scheme presented in this thread seem more complex than that.
> 
> Slom's solution is almost a literal translation to Scheme of the
> macrolet example, so the apparent complexity is probably
> subjective.

I guess so.

> It would have been comparable in length if he
> had used ASSP instead of a pattern matching style for the lookup.
> Apart from that, I find his solution a bit simpler that the Lisp
> one, in that no eval-when annotations are needed for the thing
> to work, but the same could probably have been done in Lisp by
> making local-type-declare-aux a macro.
> 
> However, while it is true that his macro breaks hygiene a little,
> the Lisp macrolet example breaks hygiene a lot, and so to be fair
> you should really add to the Lisp example the package manipulation
> stuff needed to make it as reliable as the Scheme example, along
> the lines of your earlier message.

Easy:

(defpackage :local-types
   (:use :common-lisp)
   (:export :local-type-declare :typed-var))

(in-package :local-types)

... here comes the rest of the code ...

> You should also add, to be fair,
> code to the macrolet example to check that the syntax of the
> declarations list is correct and to raise a readable /syntax/
> error if not, as the Scheme version will do automatically.
> 
> None of the other solutions remotely approach, IMO, the elegance
> and conciseness of Aziz'z solution.

...except that it doesn't do the same.


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <62bc1lF1rb3u6U1@mid.individual.net>
Pascal Costanza wrote:
> ············@yahoo.com wrote:
>> On Feb 23, 10:49 am, Pascal Costanza <····@p-cos.net> wrote:
>>
>>> There are two alternative solutions on the same page using macrolet and
>>> symbol-macrolet, which actually work in Common Lisp and are not hard to
>>> understand once you grok environment objects and how they interact with
>>> macroexpand.
>>
>> I do not find the solution using macroexpand and eval remotely
>> simple.
> 
> I do. (The eval is actually not necessary, btw. You could just leave out 
> the quote in the symbol-macrolet form and use macroexpand directly on 
> the symbol macro. I guess the example was written at a time when 
> define-symbol-macro was not part of ANSI Common Lisp yet. With 
> define-symbol-macro, the eval workaround is not necessary anymore.)

Here is a fixed version:

(defpackage :local-types
   (:use :common-lisp)
   (:export :local-type-declare :typed-var))

(in-package :local-types)

(define-symbol-macro %local-types% ())

(defmacro local-type-declare ((&rest declarations)
                               &body forms &environment env)
   (loop for declaration in declarations do
         (assert (and (consp declaration) (null (cddr declaration))) ()
           "Local type declaration ~S is invalid." declaration))
   `(symbol-macrolet
        ((%local-types% ,(append declarations
                           (macroexpand '%local-types% env))))
      ,@forms))

(defmacro typed-var (var &environment env)
   (let ((type (assoc var (macroexpand '%local-types% env))))
     (if type `(the ,(cadr type) ,var) var)))


100% pure Common Lisp. ;)


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Slom
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <ce1b16d9-7deb-41b8-9d1c-9a70dc0f9173@72g2000hsu.googlegroups.com>
On Feb 23, 8:55 pm, Pascal Costanza <····@p-cos.net> wrote:
> Pascal Costanza wrote:
> > ············@yahoo.com wrote:
> >> On Feb 23, 10:49 am, Pascal Costanza <····@p-cos.net> wrote:
>
> >>> There are two alternative solutions on the same page using macrolet and
> >>> symbol-macrolet, which actually work in Common Lisp and are not hard to
> >>> understand once you grok environment objects and how they interact with
> >>> macroexpand.
>
> >> I do not find the solution using macroexpand and eval remotely
> >> simple.
>
> > I do. (The eval is actually not necessary, btw. You could just leave out
> > the quote in the symbol-macrolet form and use macroexpand directly on
> > the symbol macro. I guess the example was written at a time when
> > define-symbol-macro was not part of ANSI Common Lisp yet. With
> > define-symbol-macro, the eval workaround is not necessary anymore.)
>
> Here is a fixed version:
>
> (defpackage :local-types
>    (:use :common-lisp)
>    (:export :local-type-declare :typed-var))
>
> (in-package :local-types)
>
> (define-symbol-macro %local-types% ())
>
> (defmacro local-type-declare ((&rest declarations)
>                                &body forms &environment env)
>    (loop for declaration in declarations do
>          (assert (and (consp declaration) (null (cddr declaration))) ()
>            "Local type declaration ~S is invalid." declaration))
>    `(symbol-macrolet
>         ((%local-types% ,(append declarations
>                            (macroexpand '%local-types% env))))
>       ,@forms))
>
> (defmacro typed-var (var &environment env)
>    (let ((type (assoc var (macroexpand '%local-types% env))))
>      (if type `(the ,(cadr type) ,var) var)))
>
> 100% pure Common Lisp. ;)
>
> Pascal
>

you have a BUG here:

> (and (consp declaration) (null (cddr declaration)))

and btw. does it handle something like ...

(let ((x 123))
  (local-type-declare ((x integer))
    (let ((x "123"))
      (typed-var x)))) ;; => should *not* be (the integer x) !!!

if not, how would you make this work?

Slom
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <62bpikF21drciU1@mid.individual.net>
Slom wrote:
> On Feb 23, 8:55 pm, Pascal Costanza <····@p-cos.net> wrote:
>> Pascal Costanza wrote:
>>> ············@yahoo.com wrote:
>>>> On Feb 23, 10:49 am, Pascal Costanza <····@p-cos.net> wrote:
>>>>> There are two alternative solutions on the same page using macrolet and
>>>>> symbol-macrolet, which actually work in Common Lisp and are not hard to
>>>>> understand once you grok environment objects and how they interact with
>>>>> macroexpand.
>>>> I do not find the solution using macroexpand and eval remotely
>>>> simple.
>>> I do. (The eval is actually not necessary, btw. You could just leave out
>>> the quote in the symbol-macrolet form and use macroexpand directly on
>>> the symbol macro. I guess the example was written at a time when
>>> define-symbol-macro was not part of ANSI Common Lisp yet. With
>>> define-symbol-macro, the eval workaround is not necessary anymore.)
>> Here is a fixed version:
>>
>> (defpackage :local-types
>>    (:use :common-lisp)
>>    (:export :local-type-declare :typed-var))
>>
>> (in-package :local-types)
>>
>> (define-symbol-macro %local-types% ())
>>
>> (defmacro local-type-declare ((&rest declarations)
>>                                &body forms &environment env)
>>    (loop for declaration in declarations do
>>          (assert (and (consp declaration) (null (cddr declaration))) ()
>>            "Local type declaration ~S is invalid." declaration))
>>    `(symbol-macrolet
>>         ((%local-types% ,(append declarations
>>                            (macroexpand '%local-types% env))))
>>       ,@forms))
>>
>> (defmacro typed-var (var &environment env)
>>    (let ((type (assoc var (macroexpand '%local-types% env))))
>>      (if type `(the ,(cadr type) ,var) var)))
>>
>> 100% pure Common Lisp. ;)
>>
>> Pascal
>>
> 
> you have a BUG here:
> 
>> (and (consp declaration) (null (cddr declaration)))

Not quite. The purpose of the assert form is to signal an error anyway. 
But you're right. Easy to fix:

(assert (ignore-errors (null (cddr declaration))))

> and btw. does it handle something like ...
> 
> (let ((x 123))
>   (local-type-declare ((x integer))
>     (let ((x "123"))
>       (typed-var x)))) ;; => should *not* be (the integer x) !!!
> 
> if not, how would you make this work?

This requires more work. (Yes, I'm hand-waving here.)


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <62bs63F22ou3nU1@mid.individual.net>
Pascal Costanza wrote:

>> and btw. does it handle something like ...
>>
>> (let ((x 123))
>>   (local-type-declare ((x integer))
>>     (let ((x "123"))
>>       (typed-var x)))) ;; => should *not* be (the integer x) !!!
>>
>> if not, how would you make this work?
> 
> This requires more work. (Yes, I'm hand-waving here.)

Well, this is actually another version of the problem of referential 
opacity. The Common Lisp solution is simple: Don't use the same name 
again, this is your code anyway.

(let ((x 123))
   (local-type-declare ((x integer))
     (let ((y "123"))
       (typed-var x))))

The documentation for local-type-declare would specify that the type 
declaration holds for _any_ variable named x in the given lexical scope.

["This require more work" refers to a different solution.]


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Abdulaziz Ghuloum
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fpqefl$9vn$1@aioe.org>
Pascal Costanza wrote:

> The documentation for local-type-declare would specify that the type 
> declaration holds for _any_ variable named x in the given lexical scope.

But that's simply unacceptable in Scheme.  Sorry.  I don't
think it is news to anybody that you can pick any name you
want for any local variable without having to think about
such gotchas.

> ["This require more work" refers to a different solution.]

We already showed how the solution that requires more work
is done in Scheme.  How about showing us how it's done in CL.
For educational purposes, you know.

Aziz,,,
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <62bu11F21tsfjU1@mid.individual.net>
Abdulaziz Ghuloum wrote:
> Pascal Costanza wrote:
> 
>> The documentation for local-type-declare would specify that the type 
>> declaration holds for _any_ variable named x in the given lexical scope.
> 
> But that's simply unacceptable in Scheme. 

I know.

>> ["This require more work" refers to a different solution.]
> 
> We already showed how the solution that requires more work
> is done in Scheme.  How about showing us how it's done in CL.
> For educational purposes, you know.

Later, not now.


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <c06ad018-c2b2-4064-bffe-ad922c7dcc91@h11g2000prf.googlegroups.com>
On Feb 23, 2:55 pm, Pascal Costanza <····@p-cos.net> wrote:
>
> Here is a fixed version:
>
> (defpackage :local-types
>    (:use :common-lisp)
>    (:export :local-type-declare :typed-var))
>
> (in-package :local-types)
>
> (define-symbol-macro %local-types% ())
>
> (defmacro local-type-declare ((&rest declarations)
>                                &body forms &environment env)
>    (loop for declaration in declarations do
>          (assert (and (consp declaration) (null (cddr declaration))) ()
>            "Local type declaration ~S is invalid." declaration))
>    `(symbol-macrolet
>         ((%local-types% ,(append declarations
>                            (macroexpand '%local-types% env))))
>       ,@forms))
>
> (defmacro typed-var (var &environment env)
>    (let ((type (assoc var (macroexpand '%local-types% env))))
>      (if type `(the ,(cadr type) ,var) var)))

The following Scheme version, based on Aziz's, seems more concise:

   (define-syntax local-declare-types
     (syntax-rules ()
       [(ctxt ([var* pred*] ...) e e* ...)
        (let-syntax ([var* (lambda (form)
                             (syntax-case form ()
                               ((_ typed-var)
                                #'(if (pred* var*)
                                      var*
                                      (error 'var* "type mismatch"
                                             `(,var* is not pred*))))
                               (x (identifier? #'x) #'var*)))]
                     ...)
          e e* ...)]))

It shadows like the Lisp version:

   (let ((z 3.3))
     (local-declare-types ((z integer?))
        (local-declare-types ((z real?))
           (z typed-var))))              ;==> 3.3

It correctly raises an error for the following:

   (let ((x 123))
     (local-declare-types ((x integer))
        (let ((x "123"))
          (x typed-var))))               ;==> error

Andre
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <62bpl8F21drciU2@mid.individual.net>
············@yahoo.com wrote:
> On Feb 23, 2:55 pm, Pascal Costanza <····@p-cos.net> wrote:
>> Here is a fixed version:
>>
>> (defpackage :local-types
>>    (:use :common-lisp)
>>    (:export :local-type-declare :typed-var))
>>
>> (in-package :local-types)
>>
>> (define-symbol-macro %local-types% ())
>>
>> (defmacro local-type-declare ((&rest declarations)
>>                                &body forms &environment env)
>>    (loop for declaration in declarations do
>>          (assert (and (consp declaration) (null (cddr declaration))) ()
>>            "Local type declaration ~S is invalid." declaration))
>>    `(symbol-macrolet
>>         ((%local-types% ,(append declarations
>>                            (macroexpand '%local-types% env))))
>>       ,@forms))
>>
>> (defmacro typed-var (var &environment env)
>>    (let ((type (assoc var (macroexpand '%local-types% env))))
>>      (if type `(the ,(cadr type) ,var) var)))
> 
> The following Scheme version, based on Aziz's, seems more concise:
> 
>    (define-syntax local-declare-types
>      (syntax-rules ()
>        [(ctxt ([var* pred*] ...) e e* ...)
>         (let-syntax ([var* (lambda (form)
>                              (syntax-case form ()
>                                ((_ typed-var)
>                                 #'(if (pred* var*)
>                                       var*
>                                       (error 'var* "type mismatch"
>                                              `(,var* is not pred*))))
>                                (x (identifier? #'x) #'var*)))]
>                      ...)
>           e e* ...)]))

Yep, looks good. I have to find a better example.

> It shadows like the Lisp version:
> 
>    (let ((z 3.3))
>      (local-declare-types ((z integer?))
>         (local-declare-types ((z real?))
>            (z typed-var))))              ;==> 3.3
> 
> It correctly raises an error for the following:
> 
>    (let ((x 123))
>      (local-declare-types ((x integer))
>         (let ((x "123"))
>           (x typed-var))))               ;==> error

The semantics of the Lisp version was not to raise an error, but that's 
a detail that's easy to change in both the Scheme and the Lisp version, 
so it doesn't matter.


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Kent M Pitman
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <uoda7msxt.fsf@nhplace.com>
[ comp.lang.lisp only; http://www.nhplace.com/kent/PFAQ/cross-posting.html ]

Pascal Costanza <··@p-cos.net> writes:

> ... Another opinion from the same page is this:
> 
> "If COMPILER-LET were not part of the language, people wouldn't think
> in terms of rewriting COMPILER-LETs as MACROLETs; instead, they'd
> think of how to use MACROLET in the first place to solve their
> problems.  This is what people who now use implementations with broken
> COMPILER-LETs already do.  Since MACROLET is now used much more
> frequently than COMPILER-LET, that argues that people are much more
> familiar with MACROLET idioms than COMPILER-LET idioms."
> 
> The question whether a solution using COMPILER-LET is complex or not
> is pretty academic: A consistent specification for COMPILER-LET never
> existed, and it's unclear whether an attempt to repair it would have
> been successful.

One proof that COMPILER-LET is not as straightforward as it seems is
in the implementation of the SERIES code by Dick Waters.  Various
people, including me, have tried to fix it by source-to-source rewrite
and that's really quite hard.  Rewriting it from scratch would
probably be much easier.  The problem is that the "semantics"
implemented by COMPILER-LET is so odd that building something that is
point-by-point compatible with what COMPILER-LET did, relying on the
intended parts and not relying on the unintended parts, is very hard.

Most other uses of COMPILER-LET that I've seen were straightforward to
rewrite, but that one was so elaborate that untangling it was just
hard, mostly because it's hard to tell from the code what is intended
in order to know what parts to preserve.

(Naturally, someone is welcome to prove me wrong by rushing off and
doing the implementation quickly.  I don't doubt that it's ultimately
possible to rewrite, and if what it takes to get it finally done is
for someone to want to put me to shame, that'll be a fair trade.)

Incidentally, the unintended part is about the fact that in order to
make COMPILER-LET work in incrementally interpreted code, it does a
special bind of the variables, which means that depending on whether
the implementation is doing EVAL by doing incremental interpretation
or by prepass of minimal compilation followed by function calling, you
either will or won't see a special binding at runtime.  Which means
that it's almost as if it's non-deterministic whether a special
binding has occurred, and since sorting out dynamic variable bindings
is already capable of being tricky, it gets really, really messy.  If
what I've said here isn't enough for someone to see the issue, ask and
I'm sure someone (perhaps me, perhaps someone else) will elaborate on
another occasion.  But, bottom line, it was an icky primitive with
strange non-portable semantics to start with, and the "confusion" came
from that fact.

Using ill-defined things always starts off easy, which is what makes
them susceptible to claims that they're "more straightforward".  It's
only in the complex situations that you get into a mess.  And then the
temptation is to blame the context (e.g., the language, the user,
etc.), and not the already-well-accepted operator that never had a
chance of scaling up in the first place.
From: Abdulaziz Ghuloum
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fpq99q$o9q$1@aioe.org>
Pascal Costanza wrote:

> There are two alternative solutions on the same page using macrolet and 
> symbol-macrolet, which actually work in Common Lisp and are not hard to 
> understand once you grok environment objects and how they interact with 
> macroexpand. As I said elsewhere, they basically give you a way to do 
> macroprogramming using expansion-passing style, which is similar in 
> complexity to continuation-passing, environment-passing or other kinds 
> of xyz-passing style. 


> Especially Schemers should feel comfortable with such styles.

:-)

Your other post shows a promising idea.  I'm adopting it here in an
implementation where every local-declare-types extends the types
environment (which is initially unbound) by dispatching on the declared
variables first before calling the outer local-type-declare's
environment.

The solution is more verbose because it has to take care of two
situations: whether this is the first local-type-declare found or
whether it's an extension of an outer local-type-declare.  But anyways,
thanks for the cool idea.  (I could've probably used an association
list like you did, but TIMTWOTDIT.)

Aziz,,,


Notes: The gensym call can be replaced by Pascal's '%%typed-env%%% or
whatever one feels secure-enough with.   The gensym guarantees that the
user cannot insert a binding that interferes with the types environment
so that it can only be manipulated by typed-var and local-type-declare.
There may also be some phasing issues that Andre knows more about and
I don't care about.

(library (F)
   (export local-type-declare typed-var)
   (import (rnrs) (only (ikarus) gensym))
   (define-syntax mysecretid
     (with-syntax ([id (datum->syntax #'here (gensym))])
       (lambda (x) #''id)))
   (define-syntax typed-var
     (lambda (stx)
       (syntax-case stx ()
         [(ctxt var)
          (let ([dispatcher (datum->syntax #'ctxt mysecretid)])
            (if (free-identifier=?
                   dispatcher
                   (datum->syntax #'here mysecretid))
                (syntax-violation 'typed-var "untyped" #'var)
                (with-syntax ([d dispatcher])
                  #'(d var))))])))
   (define-syntax local-type-declare
     (lambda (stx)
       (syntax-case stx ()
         [(ctxt ([var* pred*] ...) e e* ...)
          (let ([dispatcher (datum->syntax #'ctxt mysecretid)])
            (with-syntax
              ([d dispatcher]
               [dd
                (if (free-identifier=?
                      dispatcher
                      (datum->syntax #'here mysecretid))
                    #'typed-var
                    dispatcher)])
               #'(let-syntax
                   ([d
                     (syntax-rules (var* ...)
                       [(_ var*)
                        (if (pred* var*)
                            var*
                            (error 'var* "type mismatch"))]
                       ...
                       [(_ not-found-here) (dd not-found-here)])])
                   e e* ...)))]))))
From: Abdulaziz Ghuloum
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fpqu6v$n4o$1@aioe.org>
Abdulaziz Ghuloum wrote:

> The solution is more verbose because it has to take care of two
> situations: whether this is the first local-type-declare found or
> whether it's an extension of an outer local-type-declare.  But anyways,
> thanks for the cool idea.  (I could've probably used an association
> list like you did, but TIMTWOTDIT.)

That solution was too complex IMHO.  It also has two limitations
that do not concern common lispers much (they only concern Schemers).
I have a solution, but it's so verbose that my usenet server does
not take it.  So, a challenge to Scheme Macro Gurus:  Finding the
bugs in the previous library earns you one guru point. Fixing them
earns you two guru points.

Here is a straightforward but Chez-specific solution.  It involves
binding the variables to a "typed" object in the expander environment
and querying that environment later to obtain the predicate.

Aziz,,,


(module (local-type-declare (typed-var untyped))
   (import scheme)
   (define-syntax local-type-declare
     (syntax-rules ()
       [(_ ((var* pred*) ...) e e* ...)
        (let-syntax ([var* (list 'typed #'var* #'pred*)] ...)
          e e* ...)]))
   (define-syntax untyped
     (lambda (stx)
       (lambda (r)
         (syntax-case stx ()
           [(_ var)
            (syntax-case (r #'var) ()
              [(t id pred) (eq? #'t 'typed)
               #'(untyped id)]
              [_ #'var])]))))
   (define-syntax typed-var
     (lambda (stx)
       (lambda (r)
         (syntax-case stx ()
           [(_ var)
            (syntax-case (r #'var) ()
              [(t id pred) (eq? #'t 'typed)
               #'(let ([tmp (untyped var)])
                   (if (pred tmp)
                       tmp
                       (error 'var "type mismatch ~s is not ~s"
                         tmp 'pred)))]
              [_ (error 'typed-var "not a typed var" #'var)])])))))
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <4cd23163-7866-4fa5-82fb-a96653660e9d@e60g2000hsh.googlegroups.com>
On Feb 24, 12:09 am, Abdulaziz Ghuloum <········@cee.ess.indiana.edu>
wrote:

> That solution was too complex IMHO.
> ...
> Here is a straightforward but Chez-specific solution.

Was something wrong with the solution I posted (based on your
original)?
It is not Chez-specific:

   (define-syntax local-declare-types
     (syntax-rules ()
       [(ctxt ([var* pred*] ...) e e* ...)
        (let-syntax ([var* (lambda (form)
                             (syntax-case form ()
                               ((_ typed-var)
                                #'(if (pred* var*)
                                      var*
                                      (error 'var* "type mismatch"
                                             `(,var* is not pred*))))
                               (x (identifier? #'x) #'var*)))]
                     ...)
          e e* ...)]))

with correct shadowing:

   (let ((z 3.3))
     (local-declare-types ((z integer?))
        (local-declare-types ((z real?))
           (z typed-var))))              ;==> 3.3

Andre
From: Abdulaziz Ghuloum
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fpt00r$qnn$1@aioe.org>
············@yahoo.com wrote:

> Was something wrong with the solution I posted (based on your
> original)?

I don't think it was "wrong", it was just different.  You changed the
way typed variables are referenced from (typed-var x) to (x typed-var).

But anyways, this thread has gone for far longer than necessary, so,
I'll leave it at that for now.

Aziz,,,
From: Abdulaziz Ghuloum
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fpteat$3rq$1@aioe.org>
············@yahoo.com wrote:
> On Feb 24, 12:09 am, Abdulaziz Ghuloum <········@cee.ess.indiana.edu>
> wrote:
> 
>> That solution was too complex IMHO.
>> ...
>> Here is a straightforward but Chez-specific solution.
> 
> Was something wrong with the solution I posted (based on your
> original)?

Sorry to reply again :-)

Here's my final version.  With the exception of gensym, it
should be portable.  It has correct shadowing as you want.
It also eliminates the need for using a special (typed-var x)
or (x typed-var) syntax:  all references are automatically
checked as in my original version.

This is one of the most complex macros that I've written so
far (for its size).  It also added, say, a new word to my
macro vocabulary: how to skip over from one binding to the
next.

Aziz,,,

(library (G)
   (export local-declare-type)
   (import (rnrs) (only (ikarus) gensym))

   (define-syntax identity
     (syntax-rules ()
       [(_ x) x]))

   (define-syntax local-declare-type
     (let ([mysecret (gensym)])
       (lambda (stx)
         (syntax-case stx ()
           [(_ (var pred?) e e* ...)
            (with-syntax ([(nocheck p-nocheck)
                           (let ([t0 (datum->syntax #'var mysecret)]
                                 [t1 (datum->syntax #'here mysecret)])
                             (if (free-identifier=? t0 t1)
                                 (list t0 #'identity)
                                 (list t0 t0)))])
              #'(let-syntax ([nocheck
                              (syntax-rules ()
                                [(_)   (p-nocheck var)]
                                [(_ x) (p-nocheck x)])])
                  (let-syntax ([var (identifier-syntax
                                      (if (pred? (nocheck))
                                          (nocheck)
                                          (error 'var
                                            "type mismatch")))])
                    (let-syntax ([nocheck
                                  (syntax-rules (var)
                                    [(_ var) (nocheck)]
                                    [(_ x)   (nocheck x)])])
                      e e* ...))))])))))
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <a6270bb8-4195-4024-bdc4-5b49d316dfd8@64g2000hsw.googlegroups.com>
On Feb 24, 10:56 pm, Abdulaziz Ghuloum <········@cee.ess.indiana.edu>
wrote:

> Here's my final version.  With the exception of gensym, it
> should be portable.  It has correct shadowing as you want.

Very mind-boggling!

Just a small portability note.  The way of importing gensym
is not portable to systems that check import levels.  It
should be something like

   (for (only (ikarus) gensym) expand)

where "ikarus" stands for whichever library contains your
gensym.  Also, I suspect that on some systems (not Chez),
the result of (datum->syntax #'var (gensym)) might accidentally
coincide with #'var itself.  On such systems, the macro would
not be correct in all cases.

Andre

Andre
From: Slom
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fb8c6d56-7404-4284-a6e8-0a53fff2746c@q70g2000hsb.googlegroups.com>
While the real experts are doing mind-boggling magic, I thought I
should fix the first example I gave in this thread. Turns out I only
really missed one un-syntax ;( So here is my last add-on to this
thread then.

(define-syntax declare-types
  (lambda (x)
    (syntax-case x ()
      ((?kw ((?def-id ?type) ...) . ?body)
       (every identifier? (syntax->list #'(?def-id ...)))
       (with-syntax ((typed-var (datum->syntax-object #'?kw 'typed-
var)))
         #'(let-syntax ((typed-var
                         (lambda (x)
                           (syntax-case x ()
                             ((_ ?use-id)
                              (and (identifier? #'?use-id)
                                   (free-identifier=? #'?use-id #'?def-
id))
                              #'(the ?type ?use-id))
                             ...
                             ((_ ?use-id)
                              #'(typed-var ?use-id))))))
             . ?body))))))

(define-syntax typed-var
  (lambda (x)
    (syntax-case x ()
      ((_ ?use-id)
       (identifier? #'?use-id)
       #'?use-id))))
From: Abdulaziz Ghuloum
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fpv62p$81l$1@aioe.org>
············@yahoo.com wrote:

> Just a small portability note.  The way of importing gensym
> is not portable to systems that check import levels.

Well, maybe such implementation exports its gensym for all
levels. :-)

> Also, I suspect that on some systems (not Chez),
> the result of (datum->syntax #'var (gensym)) might accidentally
> coincide with #'var itself.  On such systems, the macro would
> not be correct in all cases.

That would be the fault of the gensym (which is supposed to,
by definition, "gen"erate a "sym"bol that does not already
exist).  The (not Chez) systems with broken gensyms would be
more useful if they fix their gensym implementations.

Aziz,,,
From: leppie
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <paudnZHyqd7sll7aRVnyiQA@saix.net>
"Abdulaziz Ghuloum" <········@cee.ess.indiana.edu> wrote in message 
·················@aioe.org...
>
> (library (G)
>   (export local-declare-type)
>   (import (rnrs) (only (ikarus) gensym))
>
>   (define-syntax identity
>     (syntax-rules ()
>       [(_ x) x]))
>
>   (define-syntax local-declare-type
>     (let ([mysecret (gensym)])
>       (lambda (stx)
>         (syntax-case stx ()
>           [(_ (var pred?) e e* ...)
>            (with-syntax ([(nocheck p-nocheck)
>                           (let ([t0 (datum->syntax #'var mysecret)]
>                                 [t1 (datum->syntax #'here mysecret)])
>                             (if (free-identifier=? t0 t1)
>                                 (list t0 #'identity)
>                                 (list t0 t0)))])
>              #'(let-syntax ([nocheck
>                              (syntax-rules ()
>                                [(_)   (p-nocheck var)]
>                                [(_ x) (p-nocheck x)])])
>                  (let-syntax ([var (identifier-syntax
>                                      (if (pred? (nocheck))
>                                          (nocheck)
>                                          (error 'var
>                                            "type mismatch")))])
>                    (let-syntax ([nocheck
>                                  (syntax-rules (var)
>                                    [(_ var) (nocheck)]
>                                    [(_ x)   (nocheck x)])])
>                      e e* ...))))])))))

For a nicer/better error message:

(assertion-violation 'var "type mismatch" 'pred? (nocheck))

Cheers

leppie 
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <62actfF1v5konU1@mid.individual.net>
Slom wrote:
> On Feb 22, 3:19 pm, Pascal Costanza <····@p-cos.net> wrote:
>>> would you like to share some of your "complex ones", otherwise this
>>> will *stay* handwaving for the time being. Maybe also some examples
>>> were you tried (and failed) to implement your complex macros in
>>> syntax-case.
>> I'd like to see a syntax-case (or other of the hygienic macro systems)
>> version of the kind of macros discussed athttp://www.lispworks.com/documentation/HyperSpec/Issues/iss066_w.htm
> 
> that whole document is an argument *for* proper hygiene and phase-
> separation ... got more?

Well, the follow-up discussion among what I presume to be experts in 
using hygienic macro systems apparently proves the opposite.

Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Slom
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <8ac222af-3958-424d-a665-1860c66a9cd6@d21g2000prf.googlegroups.com>
On Feb 23, 12:04 pm, Pascal Costanza <····@p-cos.net> wrote:
> Slom wrote:
> > On Feb 22, 3:19 pm, Pascal Costanza <····@p-cos.net> wrote:
> >>> would you like to share some of your "complex ones", otherwise this
> >>> will *stay* handwaving for the time being. Maybe also some examples
> >>> were you tried (and failed) to implement your complex macros in
> >>> syntax-case.
> >> I'd like to see a syntax-case (or other of the hygienic macro systems)
> >> version of the kind of macros discussed athttp://www.lispworks.com/documentation/HyperSpec/Issues/iss066_w.htm
>
> > that whole document is an argument *for* proper hygiene and phase-
> > separation ... got more?
>
> Well, the follow-up discussion among what I presume to be experts in
> using hygienic macro systems apparently proves the opposite.

wow thanks ... by your standard we sure have a lot of "experts" on our
side :)

Now maybe we should just add an issue to our standard because this is
so straightforward.

Christian
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <62bprsF22ao23U1@mid.individual.net>
Slom wrote:
> On Feb 23, 12:04 pm, Pascal Costanza <····@p-cos.net> wrote:
>> Slom wrote:
>>> On Feb 22, 3:19 pm, Pascal Costanza <····@p-cos.net> wrote:
>>>>> would you like to share some of your "complex ones", otherwise this
>>>>> will *stay* handwaving for the time being. Maybe also some examples
>>>>> were you tried (and failed) to implement your complex macros in
>>>>> syntax-case.
>>>> I'd like to see a syntax-case (or other of the hygienic macro systems)
>>>> version of the kind of macros discussed athttp://www.lispworks.com/documentation/HyperSpec/Issues/iss066_w.htm
>>> that whole document is an argument *for* proper hygiene and phase-
>>> separation ... got more?
>> Well, the follow-up discussion among what I presume to be experts in
>> using hygienic macro systems apparently proves the opposite.
> 
> wow thanks ... by your standard we sure have a lot of "experts" on our
> side :)

:)

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Abdulaziz Ghuloum
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fpqd92$66h$1@aioe.org>
Pascal Costanza wrote:
> Slom wrote:
>>
>> that whole document is an argument *for* proper hygiene and phase-
>> separation ... got more?
> 
> Well, the follow-up discussion among what I presume to be experts in 
> using hygienic macro systems apparently proves the opposite.
> 

Andre and I are trying to solve your problem while still
preserving hygiene; which is another way of saying that we
were solving a different problem than the one you presented.
If we wanted to come up with a non-hygienic answer, there
wouldn't have been a discussion.  You cannot take than our
discussion as argument for or against hygiene.

Aziz,,,
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <62bsh6F22jk9sU1@mid.individual.net>
Abdulaziz Ghuloum wrote:
> Pascal Costanza wrote:
>> Slom wrote:
>>>
>>> that whole document is an argument *for* proper hygiene and phase-
>>> separation ... got more?
>>
>> Well, the follow-up discussion among what I presume to be experts in 
>> using hygienic macro systems apparently proves the opposite.
>>
> 
> Andre and I are trying to solve your problem while still
> preserving hygiene; which is another way of saying that we
> were solving a different problem than the one you presented.
> If we wanted to come up with a non-hygienic answer, there
> wouldn't have been a discussion.  You cannot take than our
> discussion as argument for or against hygiene.

My claim was that complex macros are easier to write in Common Lisp than 
in the hygienic macro systems in Scheme. For that, it doesn't matter 
whether the resulting macros preserve hygiene or not.

(You have come up with an elegant solution in Scheme for the example I 
have given, so that example doesn't back my claim. [1] I have to find a 
better one.)


Pascal

[1] Although I still prefer my version, but that's irrelevant.

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Abdulaziz Ghuloum
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fpqf4c$bvl$1@aioe.org>
Pascal Costanza wrote:

> My claim was that complex macros are easier to write in Common Lisp than 
> in the hygienic macro systems in Scheme. For that, it doesn't matter 
> whether the resulting macros preserve hygiene or not.

I wasn't following the rules of the games from the start.

> (You have come up with an elegant solution in Scheme for the example I 
> have given, so that example doesn't back my claim. [1] I have to find a 
> better one.)

Or you can play our game now and come up with a CL equivalent
to what we came up with!  I mean, it's not fair that you always
come up with challenges and make it up to us to prove you wrong.

So, you think of another challenge when it's your turn to play.

Aziz,,,
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <62bu5gF21tsfjU2@mid.individual.net>
Abdulaziz Ghuloum wrote:
> Pascal Costanza wrote:
> 
>> My claim was that complex macros are easier to write in Common Lisp 
>> than in the hygienic macro systems in Scheme. For that, it doesn't 
>> matter whether the resulting macros preserve hygiene or not.
> 
> I wasn't following the rules of the games from the start.
> 
>> (You have come up with an elegant solution in Scheme for the example I 
>> have given, so that example doesn't back my claim. [1] I have to find 
>> a better one.)
> 
> Or you can play our game now and come up with a CL equivalent
> to what we came up with!  I mean, it's not fair that you always
> come up with challenges and make it up to us to prove you wrong.

Hey, I already admitted that you won this round, haven't I? ;)


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <7ca14378-9c95-430a-9dd3-696e9d9370a4@p73g2000hsd.googlegroups.com>
On Feb 22, 9:19 am, Pascal Costanza <····@p-cos.net> wrote:

> I'd like to see a syntax-case (or other of the hygienic macro systems)
> version of the kind of macros discussed at
> athttp://www.lispworks.com/documentation/HyperSpec/Issues/iss066_w.htm

From that page:

  "The intent of COMPILER-LET was to permit information to be
communicated
   between macros by use of dynamic variables at macroexpansion time.
   It was not necessary to the intended uses of COMPILER-LET that such
   variables ever be bound at execution time."

R6RS modules were designed precisely for this kind of thing.
The following has been tested in Larceny:

   (library (expand-time-registry)
     (export register-types lookup-type)
     (import (rnrs))
     (define types '())
     (define (register-types declarations)
       (set! types (append declarations types)))
     (define (lookup-type x)
       (cond ((assp (lambda (y) (free-identifier=? x y)) types)
              => cadr)
             (else (syntax-violation 'typed-var "Unknown type" x)))))

   (import (rnrs)
           (for (expand-time-registry) expand))

   (define-syntax local-type-declare
     (lambda (form)
       (register-types (cadr form))
       #`(let () #,@(cddr form))))

   (define-syntax typed-var
     (lambda (form)
       (let* ((x (cadr form))
              (predicate (lookup-type x)))
         #`(if (#,predicate #,x) #,x (error "Type violation: "
'#,x)))))

   (define (f x) (local-type-declare ((x integer?)) (typed-var x)))

   (f 1)   ;==> 1
   (f 1.1) ;==> Error: Type violation: x

The line "(for (expand-time-registry) expand)" in the import precisely
ensures that the expand-time registry is available at macroexpansion-
time,
and only at macroexpansion-time, and guarantees that it can be left
out of the runtime image.  The (for --- expand) annotations take
the place of Lisp's eval-when annotations.

Even better: the system checks syntactically that the registry is not
mistakenly used in execution-time code.  An error would be raised at
expand/compile time if that happened.  This is very helpful, since it
is
easy to make phase mistakes.  For example, the following wrong
version
of local-type-declare would raise an immediate syntax error, since
REGISTER-TYPES is mistakenly inserted in runtime code:

  (define-syntax local-type-declare
     (lambda (form)
       #`(begin (register-types #,(cadr form))
                (let () #,@(cddr form))))

Similarly, a syntax error would have been raised if the registry
had not been imported for "expand", or if you had tried to use
an ordinary toplevel global variable (which does not exist at
expand-time) as a registry.

Even more helpful is the fact that this error gets checked even in
interpreted code, despite the fact that, in an interpreter, expand-
time
and runtime objects are all available together.  The fact that you
cannot even make the mistake in the interpreter helps ensure that
interpreted and compiled programs will have the same behaviour.
In other words, your interpreted program will not suddenly break when
you decide to compile it.

Andre
From: Abdulaziz Ghuloum
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fpn2t9$g7j$1@aioe.org>
The solution for local-declare-types can be written in a simpler
and more portable fashion as:

(define-syntax local-declare-types
   (syntax-rules ()
     [(ctxt ([var* pred*] ...) e e* ...)
      (let-syntax ([var* (identifier-syntax
                           (if (pred* var*)
                               var*
                               (error 'var* "type mismatch"
                                      `(,var* is not pred*))))]
                   ...)
        e e* ...)]))

(define (f x y)
   (local-declare-types ((x integer?) (y integer?))
     (let ((z 3))
       (local-declare-types ((z integer?))
          (+ x y z)))))

(f 1 1.1)
=>
Error: y: type mismatch (1.1 is not integer?)

Personally, I would vote for (COMPILER-LET-CONFUSION:ELIMINATE).
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <bc0f647a-6905-4a42-b88b-aed78c36cbc4@e23g2000prf.googlegroups.com>
On Feb 22, 1:05 pm, Abdulaziz Ghuloum <········@cee.ess.indiana.edu>
wrote:

> (define-syntax local-declare-types
>    (syntax-rules ()
>      [(ctxt ([var* pred*] ...) e e* ...)
>       (let-syntax ([var* (identifier-syntax
>                            (if (pred* var*)
>                                var*
>                                (error 'var* "type mismatch"
>                                       `(,var* is not pred*))))]
>                    ...)
>         e e* ...)]))

Let me pointout the following interesting behaviour of your
proposed solution:

  (let ((z 3.3))
     (local-declare-types ((z integer?))
        (local-declare-types ((z real?))
           z)))

    ==> "type mismatch" (3.3 is not integer?)

How would you write the macro to test only the innermost
predicate?

Andre
From: Abdulaziz Ghuloum
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fpnvj2$ca0$1@aioe.org>
············@yahoo.com wrote:

> Let me pointout the following interesting behaviour of your
> proposed solution:
> 
>   (let ((z 3.3))
>      (local-declare-types ((z integer?))
>         (local-declare-types ((z real?))
>            z)))
> 
>     ==> "type mismatch" (3.3 is not integer?)
> 
> How would you write the macro to test only the innermost
> predicate?

I thought that's what you just declared z to be: a real integer.
Anyways, I don't have a portable way but I do have a non-portable
way (Chez Scheme specific) if you're interested.

But tell me first, why do both of the following expressions pass,
even though z (3.3) was declared to be "integer?" within the
scope of the outer local-type-declare?

(let ((z 3.3))
   (local-type-declare ((z integer?))
     (local-type-declare ((z real?))
       (display (typed-var z))
       (newline))
     (display (typed-var z)) ; <=== HERE
     (newline)))

(let ((z 3.3))
   (local-type-declare ((z integer?))
     (display (typed-var z)) ; <=== HERE
     (newline)
     (local-type-declare ((z real?))
       (display (typed-var z))
       (newline))))

We've been through this so many times before, so I don't think I
need to repeat any of the arguments for how unwieldy it is to try
to manage and properly scope these compile-time side effects.

Aziz,,,
From: Abdulaziz Ghuloum
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fpo0iv$f7t$1@aioe.org>
Just for the record, these are the steps I used to load Andre's
library, macros, and examples.


$ larceny -err5rs
Larceny v0.961 "Fluoridation" (Jan  2 2008 04:30:22, precise:Posix 
Unix:unified)
larceny.heap, built on Wed Jan  2 04:41:29 EST 2008
ERR5RS mode (no libraries have been imported)

 > (library (expand-time-registry)
    (export register-types lookup-type)
    (import (rnrs))
    (define types '())
    (define (register-types declarations)
      (set! types (append declarations types)))
    (define (lookup-type x)
      (cond ((assp (lambda (y) (free-identifier=? x y)) types)
             => cadr)
            (else (syntax-violation 'typed-var "Unknown type" x)))))
Autoloading (rnrs)
Autoloading (rnrs enums)
Autoloading (rnrs lists)
Autoloading (rnrs syntax-case)
Autoloading (rnrs hashtables)
Autoloading (rnrs arithmetic bitwise)
Autoloading (rnrs programs)
Autoloading (rnrs files)
Autoloading (rnrs io ports)
Autoloading (larceny deprecated)
Autoloading (rnrs conditions)
Autoloading (rnrs exceptions)
Autoloading (rnrs records syntactic)
Autoloading (err5rs records procedural)
Autoloading (rnrs records procedural)
Autoloading (rnrs control)
Autoloading (rnrs sorting)
Autoloading (rnrs bytevectors)
Autoloading (rnrs unicode)

 > (import (rnrs) (for (expand-time-registry) expand))

 > (define-syntax local-type-declare
   (lambda (form)
     (register-types (cadr form))
     #`(let () #,@(cddr form))))

 > (define-syntax typed-var
   (lambda (form)
     (let* ((x (cadr form))
            (predicate (lookup-type x)))
       #`(if (#,predicate #,x) #,x (error "Type violation: " '#,x)))))

 > (let ((z 3.3))
   (local-type-declare ((z integer?))
     (local-type-declare ((z real?))
       (display (typed-var z))
       (newline))
     (display (typed-var z)) ; <=== HERE
     (newline)))
3.3
3.3

 > (let ((z 3.3))
   (local-type-declare ((z integer?))
     (display (typed-var z)) ; <=== HERE
     (newline)
     (local-type-declare ((z real?))
       (display (typed-var z))
       (newline))))
3.3
3.3

 >
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <033b9841-f39b-45ef-9609-c8b9da818c02@h25g2000hsf.googlegroups.com>
On Feb 22, 9:14 pm, Abdulaziz Ghuloum <········@cee.ess.indiana.edu>
wrote:
> ············@yahoo.com wrote:
> > Let me pointout the following interesting behaviour of your
> > proposed solution:
>
> >   (let ((z 3.3))
> >      (local-declare-types ((z integer?))
> >         (local-declare-types ((z real?))
> >            z)))
>
> >     ==> "type mismatch" (3.3 is not integer?)
>
> > How would you write the macro to test only the innermost
> > predicate?
>
> I thought that's what you just declared z to be: a real integer.
> Anyways, I don't have a portable way but I do have a non-portable
> way (Chez Scheme specific) if you're interested.

I did not say it was not a feature ;)  However, it behaves
differently from the Lisp solutions.

I believe there is a portable way to have nested declarations shadow
as in the Lisp case.  In particular, the following should be
R6RS-portable:

   (library (registry)
     (export register lookup)
     (import (rnrs))
     (define types '())
     (define (register declarations)
       (set! types (append declarations types)))
     (define (lookup x)
       (cond ((assp (lambda (y) (free-identifier=? x y)) types)
              => cadr)
             (else (syntax-violation 'typed-var "Unknown type" x)))))

   (import (rnrs)
           (for (registry) expand))

   (define-syntax local-declare-types
     (syntax-rules ()
       ((_ ((var* pred*) ...) e e* ...)
        (let-syntax ((var* (identifier-syntax var*)) ...)
          (let-syntax
              ((expand-time
                (begin (register #'((var* pred*) ...))
                       ;; for portability (never called)
                       values)))
            e e* ...)))))

   (define-syntax typed-var
     (lambda (form)
       (syntax-case form ()
         ((_ x)
          (with-syntax ((predicate (lookup #'x)))
            #`(if (predicate x)
                  x
                  (error 'typed-var "Type violation: " 'x)))))))

> We've been through this so many times before, so I don't think I
> need to repeat any of the arguments for how unwieldy it is to try
> to manage and properly scope these compile-time side effects.

It is indeed subtle.  But the above solution corrects the bugs you
pointed out in the prior version.

Andre
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <62ado5F226ohrU1@mid.individual.net>
············@yahoo.com wrote:
> On Feb 22, 9:19 am, Pascal Costanza <····@p-cos.net> wrote:
> 
>> I'd like to see a syntax-case (or other of the hygienic macro systems)
>> version of the kind of macros discussed at
>> athttp://www.lispworks.com/documentation/HyperSpec/Issues/iss066_w.htm
> 
> From that page:
> 
>   "The intent of COMPILER-LET was to permit information to be
> communicated
>    between macros by use of dynamic variables at macroexpansion time.
>    It was not necessary to the intended uses of COMPILER-LET that such
>    variables ever be bound at execution time."
> 
> R6RS modules were designed precisely for this kind of thing.
> The following has been tested in Larceny:
> 
>    (library (expand-time-registry)
>      (export register-types lookup-type)
>      (import (rnrs))
>      (define types '())
>      (define (register-types declarations)
>        (set! types (append declarations types)))
>      (define (lookup-type x)
>        (cond ((assp (lambda (y) (free-identifier=? x y)) types)
>               => cadr)
>              (else (syntax-violation 'typed-var "Unknown type" x)))))
> 
>    (import (rnrs)
>            (for (expand-time-registry) expand))
> 
>    (define-syntax local-type-declare
>      (lambda (form)
>        (register-types (cadr form))
>        #`(let () #,@(cddr form))))
> 
>    (define-syntax typed-var
>      (lambda (form)
>        (let* ((x (cadr form))
>               (predicate (lookup-type x)))
>          #`(if (#,predicate #,x) #,x (error "Type violation: "
> '#,x)))))
> 
>    (define (f x) (local-type-declare ((x integer?)) (typed-var x)))
> 
>    (f 1)   ;==> 1
>    (f 1.1) ;==> Error: Type violation: x

The fact that you're using side effects here looks extremely suspicious 
to me.

Is your macro stable when interactively expanding parts of your source 
code that uses it?

You append type declarations to a global variable. Do they ever get 
removed when macroexpansion leaves a lexical scope, or does that 
variable just grow all the time? This looks very inelegant to me.


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <7a8bebd2-0e4e-4b51-bcb5-994e919ce537@h11g2000prf.googlegroups.com>
On Feb 23, 6:18 am, Pascal Costanza <····@p-cos.net> wrote:

> The fact that you're using side effects here looks extremely suspicious
> to me.

Indeed, it is subtle, and there was a bug.  See my response to Aziz
for the correction.

> Is your macro stable when interactively expanding parts of your source
> code that uses it?

Yes.  Absolutely.

> You append type declarations to a global variable. Do they ever get
> removed when macroexpansion leaves a lexical scope, or does that
> variable just grow all the time? This looks very inelegant to me.

It is indeed inelegant, but it works.  It is the only way of which I
am
aware of associating any object with a lexically bound variable in
R6RS,
not just objects embeddable in code.
(Can you do this portably in Lisp for arbitrary objects?).

I believe MzScheme and Chez (?) have more elegant mechanisms, perhaps
along the lines of compiler-let, that ensure that the information is
discarded once one leaves a lexical scope.  That is a nicety, but
it is not strictly necessary.

Andre
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <62b6c1F22f8l6U2@mid.individual.net>
············@yahoo.com wrote:
> On Feb 23, 6:18 am, Pascal Costanza <····@p-cos.net> wrote:
> 
>> The fact that you're using side effects here looks extremely suspicious
>> to me.
> 
> Indeed, it is subtle, and there was a bug.  See my response to Aziz
> for the correction.
> 
>> Is your macro stable when interactively expanding parts of your source
>> code that uses it?
> 
> Yes.  Absolutely.

OK, but the list of type declarations will grow and grow...

>> You append type declarations to a global variable. Do they ever get
>> removed when macroexpansion leaves a lexical scope, or does that
>> variable just grow all the time? This looks very inelegant to me.
> 
> It is indeed inelegant, but it works.  It is the only way of which I
> am
> aware of associating any object with a lexically bound variable in
> R6RS,
> not just objects embeddable in code.
> (Can you do this portably in Lisp for arbitrary objects?).

Sure. Everything we discussed in this thread is portable Common Lisp.

(except COMPILER-LET, of course ;)


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Ken Tilton
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <47b93778$0$25040$607ed4bc@cv.net>
Abdulaziz Ghuloum wrote:
> Ken Tilton wrote:
> 
>> In a couple of messages pg has laid down a constraint on whining about 
>> Arc: only stuff that creates a problem /in practice/ is of interest.
> 
> 
> NOTHING creates a problem in practice.  

Don't be silly. Random example: OOPS capable of only single inheritance 
in an orthogonally classified world. Interfaces? Puh-leaze. Another: not 
accepting nil as false, forcing endless amounts of extra code with no 
way around it. Static typing? Enslavement to a compiler in C++ or Java? 
What's your genius painless workaround for that? Oh, sorry, you do not 
have one. Oh, wait, Java, no preprocessor let alone macro system. What 
do you call your workaround, nil or false?

Otherwise that was a clever post. :)

kenny

-- 
http://smuglispweeny.blogspot.com/
http://www.theoryyalgebra.com/

"In the morning, hear the Way;
  in the evening, die content!"
                     -- Confucius
From: Ken Tilton
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <47b93a9b$0$25017$607ed4bc@cv.net>
Ken Tilton wrote:
> 
> 
> Abdulaziz Ghuloum wrote:
> 
>> Ken Tilton wrote:
>>
>>> In a couple of messages pg has laid down a constraint on whining 
>>> about Arc: only stuff that creates a problem /in practice/ is of 
>>> interest.
>>
>>
>>
>> NOTHING creates a problem in practice.  
> 
> 
> Don't be silly. Random example: OOPS capable of only single inheritance 
> in an orthogonally classified world. Interfaces? Puh-leaze. Another: not 
> accepting nil as false, forcing endless amounts of extra code with no 
> way around it. Static typing? Enslavement to a compiler in C++ or Java? 
> What's your genius painless workaround for that? Oh, sorry, you do not 
> have one. Oh, wait, Java, no preprocessor let alone macro system. What 
> do you call your workaround, nil or false?
> 
> Otherwise that was a clever post. :)

Wait! Don't go! Manual memory management and pointer dereferencing in C? 
Not a problem in practice? You have a scoop.

:)

kenny

-- 
http://smuglispweeny.blogspot.com/
http://www.theoryyalgebra.com/

"In the morning, hear the Way;
  in the evening, die content!"
                     -- Confucius
From: Damien Kick
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <13ruur5pookpu47@corp.supernews.com>
Ken Tilton wrote:

> In a couple of messages pg has laid down a constraint on whining about 
> Arc: only stuff that creates a problem /in practice/ is of interest.

I've worked on C++ code, maintaining and updating existing code, that 
still used ellipsis and va_args.

Foo bar(const char* format, ...);
Foo bar(const char* format, va_list ap);

There was a case in which a new variation was added but only the 
ellipsis version was written, by mistake.

Baz qux(const char* format, ...);

And then there was a mistaken use of it, something like the following. 
I forget exactly what, but it was close to this...

Duff beer(const char* format, ...)
{
     va_list args;
     int count = count_args(format);
     va_start(arg_list, count);
     // For some reason, do something with some of the args
     // but not all and then pass to qux to process the rest
     qux(format, args);
     va_end(args);
}

Passing va_args into the ellipsis of qux caused Bad Things to happen. 
What had brought my attention to the problem was that this misuse had 
eventually lead to a program crashing.  After having debugged the 
problem, I went to a technical lead and asked if perhaps we could stop 
using ellipsis in function interfaces, as they're not type safe and 
their use could lead to problems.  His response was, "well, yeah, in 
theory."

Groucho: Doctor, it hurts when I do this.

As is the case with so many things, what is "in theory" and what is "in 
practice" is in the eye of the beholder.  Even after my having pointed 
out that "in theory" had just left a core file for me to debug, he was 
uninterested.  Sure, as long as nobody ever does anything that hurts...
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <61rel7F20ibkaU1@mid.individual.net>
Jens Axel Soegaard wrote:
> Pascal Costanza wrote:
> 
>> The problem can be relatively easily circumvented in Common Lisp by 
>> using the package system and choosing names more carefully. After all, 
>> the following actually does what you expect:
> 
>> If Common Lisp had a module system instead of a package system, and if 
>> Common Lisp were a Lisp-1 instead of a Lisp-2, referential 
>> transparency would be a much more pressing issue. [1]
>>
>> Nevertheless, hygienic macro systems are strictly more powerful in 
>> that regard than defmacro-style macro systems.
> 
> 
> I wonder how long it takes the Arcers (?) to realize the problems.

Good question. What's the experience with define-macro in Scheme 
implementations. Does the problem actually occur? A lot?


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: John Thingstad
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <op.t6orxgksut4oq5@pandora.alfanett.no>
P� Sun, 17 Feb 2008 02:43:20 +0100, skrev Pascal Costanza <··@p-cos.net>:

>
> No, that's not enough. What you list here solves the problems of  
> unintended variable capture, and order and number of evaluations.  
> Referential transparency is something else, though.
>
> Consider:
>
> (let ((x 42))
>    (macrolet ((foo () 'x))
>      (let ((x 4711))
>        (foo))))
>

Right you are.
You have given me something to thing about..
I was thinging of a solution like..

(let ((x 42))
   (capture (x)
     (macrolet ((foo () 'x))
       (let ((x 4711))
         (foo))))))

42

But the realized I needed special handeling for 'special' variables...
Guess I'll think some more..

--------------
John Thingstad
From: John Thingstad
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <op.t6otdtsput4oq5@pandora.alfanett.no>
P� Sun, 17 Feb 2008 21:45:06 +0100, skrev John Thingstad  
<·······@online.no>:

> P� Sun, 17 Feb 2008 02:43:20 +0100, skrev Pascal Costanza <··@p-cos.net>:
>
>>
>> No, that's not enough. What you list here solves the problems of  
>> unintended variable capture, and order and number of evaluations.  
>> Referential transparency is something else, though.
>>
>> Consider:
>>
>> (let ((x 42))
>>    (macrolet ((foo () 'x))
>>      (let ((x 4711))
>>        (foo))))
>>
>
> Right you are.
> You have given me something to thing about..
> I was thinging of a solution like..
>
> (let ((x 42))
>    (capture (x)
>      (macrolet ((foo () 'x))
>        (let ((x 4711))
>          (foo))))))
>
> 42
>
> But the realized I needed special handeling for 'special' variables...
> Guess I'll think some more..
>


I should add I would use a code walker and the fact that the macrolet  
hasn't expanded yet to substitute the variable with a unique one.

--------------
John Thingstad
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <61rne3F20m7leU1@mid.individual.net>
John Thingstad wrote:
> P� Sun, 17 Feb 2008 21:45:06 +0100, skrev John Thingstad 
> <·······@online.no>:
> 
>> P� Sun, 17 Feb 2008 02:43:20 +0100, skrev Pascal Costanza <··@p-cos.net>:
>>
>>>
>>> No, that's not enough. What you list here solves the problems of 
>>> unintended variable capture, and order and number of evaluations. 
>>> Referential transparency is something else, though.
>>>
>>> Consider:
>>>
>>> (let ((x 42))
>>>    (macrolet ((foo () 'x))
>>>      (let ((x 4711))
>>>        (foo))))
>>>
>>
>> Right you are.
>> You have given me something to thing about..
>> I was thinging of a solution like..
>>
>> (let ((x 42))
>>    (capture (x)
>>      (macrolet ((foo () 'x))
>>        (let ((x 4711))
>>          (foo))))))
>>
>> 42
>>
>> But the realized I needed special handeling for 'special' variables...
>> Guess I'll think some more..
>>
> 
> 
> I should add I would use a code walker and the fact that the macrolet 
> hasn't expanded yet to substitute the variable with a unique one.

Yes, that's what hygienic macro systems typically do.

Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: John Thingstad
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <op.t6oy4jrsut4oq5@pandora.alfanett.no>
P� Sun, 17 Feb 2008 22:31:47 +0100, skrev Pascal Costanza <··@p-cos.net>:

>
> Yes, that's what hygienic macro systems typically do.
>
> Pascal
>

Indeed but explicitly. I am talking about by protocol. But I still have to  
consider special varaibles.

--------------
John Thingstad
From: Kaz Kylheku
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <0b15d10b-d03c-4e37-a069-a407c65c3f71@u72g2000hsf.googlegroups.com>
On Feb 16, 5:43 pm, Pascal Costanza <····@p-cos.net> wrote:
> John Thingstad wrote:
> > På Sat, 16 Feb 2008 21:32:26 +0100, skrev <············@yahoo.com>:
>
> >> is simply being out of date.  Scheme macros are considered by Schemers
> >> to be more robust than Lisp defmacros, given the referential
> >> transparency guarantees of Scheme macros, although I know Lispers tend
> >> not to care
> >> about this issue.
>
> > We care. We just take care of it through protocol of writing.
> > gensym is a bit lightweight. With the help of a couple of macroes named
> > 'with-unique-names' and 'rebinding' it is fairly easy to write
> > referentially transparent code. Rebinding for rebinding input variables
> > so they are evaluated before use. with-unique-values for introducing new
> > variables.
>
> [...]
>
> > This seems to cover most cases.
>
> No, that's not enough. What you list here solves the problems of
> unintended variable capture, and order and number of evaluations.
> Referential transparency is something else, though.
>
> Consider:
>
> (let ((x 42))
>    (macrolet ((foo () 'x))
>      (let ((x 4711))
>        (foo))))


The problem with this is that it's dumb for a macro expansion to
capture material from the site of the macro definition. It continues
to be dumb even after you've solved the minor technical problems
(unraveling your symbolic references so that they don't conflict by
some trivial renaming).

This just doesn't fit into the industrial architecture of Common Lisp.
The reasons why it doesn't fit have a lot to do with why we have cruft
like EVAL-WHEN, LOAD-TIME-VALUE, COMPILE-FILE and all those non-
academic things that uglify textbook examples with irrelevant software
development and deployment concerns.

Suppose I have macro M in some source file M-define.lisp. I want to
compile this M to an object file M-define.fasl.

Then I have an object file M-use.lisp which uses the macro. It
compiles to M-use.fasl.

Under this separated compilation model, how the heck can the macro
expansions in M-use.fasl refer to a lexical environment which only
exists when M-define.fasl is loaded and stuff inside it is evaluated?

During the compilation of M-use.fasl, M-define.fasl is loaded so that
the compiler has the necessary macro definitions. When M-define.fasl
is loaded into the compiler's image, the macro-defining form is
evaluated (or its compiled image), and a brand new lexical environment
is established with fresh bindings for all of the variables which
surround the definition.

Next, the material in M-use.lisp is compiled. So what happens to the
uses of macro M? Somehow these have to produce code which refers to
the lexical environment surrounding M, which is just some incidental
object that was instantiated in the compiler's memory.

This lexical environment has to be available whenever we load M-
use.fasl. It cannot just disapper when the compiler finishes running!
I should be able to take the compiled M-use.fasl and send it to
another Lisper, whos hould be able to load it into his image. The
expansions of macro M continue to refer to the lexical environment
that surrounds macro M.

And so what this means is that the compiler has to do something
totally idiotic: it has to create closures which capture that lexical
environment (as it was instantiated inside the compiler) and store
those closures inside the object file.

For undoubtedly good reasons, the CL spec says that functions are not
externalizeable objects. So this cannot work.

Why would you want it to work, anyway? Why is a closure created inside
the compiler interesting?

It's created separately every time the compiler loads the M-define
module.

If you launch separate instances of the compiler to compile other
source files, each of them will close over a separately instantiated
environment. If you want all of the macro calls to use the same
environment, you have to load it once, and then file-compile all of
the using modules.

Then what about maintaining the stuff? Suppose a bug is found inside
some of the local functions that the macro uses. You can't rewrite
these functions and reload them, because at the macro-expansion sites,
they are locked up as closures. Loading a new version of M-define.fasl
into an image does nothing; it instantiates a new M macro with a brand
new lexical environment. Only new expansions of M receive any benefit.

This is why in Common Lisp, you want macros referencing proper package
symbols. If you want a macro expansion to use helper functions, you
have it call a proper global API through symbolic references, not
through anonymous closures. (And use package-qualified symbols to
solve the trivial name clash problem). If you want helper variables in
the macro module, you use specials. Specials resolve to the same
instance when you load the macro module multiple times. With DEFVAR
versus DEFMACRO, you can control which ones are reset to their initial
values, and which ones keep their current values: useful when loading
into a running app.

If a bug is found in a helper function that is widely called by macro
expansions, just fix the function, recompile the module and reload it.
The expansions use the new function.

If you want to rewrite a macro to have a different expansion which
uses different functions, you can keep the old ones working for
compatibility with existing expansions in a running image. Just
rewrite the old functions as compatibility wrappers for the new ones.
Compile the macro module, ship it to the user, who can just load it
into the image. Presto. New calls to the macro use the new expansion,
the existing expansions work with the compatibility wrapper.

In an actual software development situation, why would anyone /want/ a
macro expansion to be compiled with lexical references to helper
material?













>
> Now assume you're not allowed to change the names of the x variable
> bindings. In a defmacro-style macro system, there is no way that you can
> ensure that the code to which foo expands refers to the outer x by just
> changing the macro definition. Whatever you may try, the outer x will be
> shadowed by the inner x in the inner expansion of foo.
>
> Hygienic macro systems solve this issue. The following evaluates to 42:
>
> (let ((x 42))
>    (let-syntax ((foo (syntax-rules () ((foo) x))))
>      (let ((x 4711))
>        (foo))))
>
> The problem can be relatively easily circumvented in Common Lisp by
> using the package system and choosing names more carefully. After all,
> the following actually does what you expect:
>
> (let ((x 42))
>    (macrolet ((foo () 'x))
>      (let ((y 4711)) ; note: name changed
>        (foo))))
>
> If Common Lisp had a module system instead of a package system, and if
> Common Lisp were a Lisp-1 instead of a Lisp-2, referential transparency
> would be a much more pressing issue. [1]
>
> Nevertheless, hygienic macro systems are strictly more powerful in that
> regard than defmacro-style macro systems.
>
> Pascal
>
> [1] That's the main reason why I personally prefer packages over modules
> and Lisp-2 over Lisp-1, because I get much less nameclashes with that in
> general (not only in macros).
>
> --
> 1st European Lisp Symposium (ELS'08)http://prog.vub.ac.be/~pcostanza/els08/
>
> My website:http://p-cos.net
> Common Lisp Document Repository:http://cdr.eurolisp.org
> Closer to MOP & ContextL:http://common-lisp.net/project/closer/- Hide quoted text -
>
> - Show quoted text -
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <97fb52b4-f031-4564-a037-7abbe3842ea5@q33g2000hsh.googlegroups.com>
On Feb 19, 6:28 pm, Kaz Kylheku <········@gmail.com> wrote:

> This just doesn't fit into the industrial architecture of Common Lisp.
> The reasons why it doesn't fit have a lot to do with why we have cruft
> like EVAL-WHEN, LOAD-TIME-VALUE, COMPILE-FILE and all those non-
> academic things that uglify textbook examples with irrelevant software
> development and deployment concerns.

Those irrelevant industrial concerns have long been addressed
in Scheme, in a way that overcomes the weaknesses of the
Common Lisp cruft you mention.  This is best explained in:

http://citeseer.ist.psu.edu/flatt02composable.html,

an adaptation of which has been incorporated into R6RS.

> Under this separated compilation model, how the heck can the macro
> expansions in M-use.fasl refer to a lexical environment which only
> exists when M-define.fasl is loaded and stuff inside it is evaluated?

How the heck can a /function/ in M-use.fasl refer to a /function/
that only exists when M-define.fasl is loaded and stuff inside it
is evaluated?

Andre
From: Kaz Kylheku
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <6bb7b700-48ce-4d37-a74e-edaae73ff299@i12g2000prf.googlegroups.com>
On Feb 20, 7:41 am, ············@yahoo.com wrote:
> On Feb 19, 6:28 pm, Kaz Kylheku <········@gmail.com> wrote:
>
> > This just doesn't fit into the industrial architecture of Common Lisp.
> > The reasons why it doesn't fit have a lot to do with why we have cruft
> > like EVAL-WHEN, LOAD-TIME-VALUE, COMPILE-FILE and all those non-
> > academic things that uglify textbook examples with irrelevant software
> > development and deployment concerns.
>
> Those irrelevant industrial concerns have long been addressed
> in Scheme, in a way that overcomes the weaknesses of the
> Common Lisp cruft you mention.  This is best explained in:
>
> http://citeseer.ist.psu.edu/flatt02composable.html,
> an adaptation of which has been incorporated into R6RS.

You mean that paltry material in section 7?

Notice how it restricts exported variables: they must be immutable.
Implicitly exported variables are also immutable.

If a macro from some module generates an expansion that refers to one
of those module's private variables, that variable becomes implicitly
exported. And then, assignment to it is forbidden.

But ``immutable variable'' is an oxymoron; the correct name for such a
thing is ``literal constant''.

Literal constants trivially solve referential problems because they
can be reduced to their values and fully inlined.

This is weak. But R7RS will fix that, undoubtedly.

> > Under this separated compilation model, how the heck can the macro
> > expansions in M-use.fasl refer to a lexical environment which only
> > exists when M-define.fasl is loaded and stuff inside it is evaluated?
>
> How the heck can a /function/ in M-use.fasl refer to a /function/
> that only exists when M-define.fasl is loaded and stuff inside it
> is evaluated?

The expression (foo bar) can be compiled as a function call even if
foo has no binding. This is based on the implicit understanding that
in the future, by the time (foo bar) is evaluated, the name foo will
refer to a function. An expression can't similarly refer to lexical
variables which don't exist yet.
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <8e48e571-a58c-42b2-a646-3b04d38f3ad8@e23g2000prf.googlegroups.com>
On Feb 20, 3:10 pm, Kaz Kylheku <········@gmail.com> wrote:

> But ``immutable variable'' is an oxymoron; the correct name for such a
> thing is ``literal constant''.
> Literal constants trivially solve referential problems because they
> can be reduced to their values and fully inlined.

First, the immutability requirement is not essential - it
only facilitates some optimizations.

Then, for example, variables that will evaluate to
closures during runtime can certainly /not/ be reduced to their
values and inlined at compile-time.  In fact, a major feature of
this kind of Scheme modules is so that one does /not/
reduce stuff unnecessarily to their values at compile-time.
These modules automate a minimal, efficient, robust and
replicable use of eval-when by syntactic checks that ensure
that everything needed in a given phase will indeed be
available in that phase, and they allow stuff that are not
needed at runtime to be automatically pruned from the
runtime image.

> The expression (foo bar) can be compiled as a function call even if
> foo has no binding. This is based on the implicit understanding that
> in the future, by the time (foo bar) is evaluated, the name foo will
> refer to a function. An expression can't similarly refer to lexical
> variables which don't exist yet.

How then does your expression refer to the lexical (textual)
variable FOO, if "it doesn't exist yet"?

Inasmuch as I can parse what you are saying, It would seem
that you are misunderstanding what Scheme macros are about.
Scheme macros interpret variable references, a textual
(lexical) property of the source that of course
exists at compile time.  Scheme macros do not care about
runtime values.

For example, in the following

  (module m-define
    (export delay)
    (define-syntax delay
      (lambda (form)
         #`(make-promise (lambda () #,(cadr form)))))
    (define make-promise (lambda (thunk) .......)))

  (module m-use
    (import m-define)
    (define make-promise +)
    (delay (+ 1 2 3)))

Here modules m-define and m-use can be expanded/compiled without
needing make-promise to have a value, just like
your (foo bar) example did not need FOO to have a value
to do the compilation.  The result of the expansion/compilation
is equivalent to:

  ; m-define object code:

  (define m-define:make-promise (lambda (thunk) .......)))

  ; m-use object code:

  (define m-use:make-promise +)
  (m-define:make-promise (lambda () (+ 1 2 3)))

Note that we have finished macro expansion without needing
make-promise to have a value.  We have played a game with
names of variables, not values.  Due to the way Scheme
macros work, the last line of m-use refers to the correct
m-define:make-promise, so that the meaning of DELAY does not
get corrupted.  This is simply correct lexical scoping, and
that is all that we are advocating.

Andre
From: Abdulaziz Ghuloum
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fpi2vv$qeg$1@aioe.org>
Kaz Kylheku wrote:

> Notice how it restricts exported variables: they must be immutable.
> Implicitly exported variables are also immutable.

1. That restriction is not essential and restricting exports
    to immutable variables is a design choice.  Whether it is
    the right design choice is besides the issue.

2. If you don't know how to write define-mutable, then just
    say so.  With define-mutable, you can define, export,
    import, reference, and assign (via set!) to a "mutable"
    in both exporting and importing modules.

3. Even if the system gave you mutable exports, you can still
    write define-immutable that gives you immutable variables.
From: Abdulaziz Ghuloum
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fpi3kp$so7$1@aioe.org>
Kaz Kylheku wrote:

> But ``immutable variable'' is an oxymoron; the correct name for such a
> thing is ``literal constant''.
> 
> Literal constants trivially solve referential problems because they
> can be reduced to their values and fully inlined.

So, if all exports are immutable,
   and all immutables are literal constants
   and all literal constants can be reduced to values
And, all scheme modules have is immutable exports
Then, all scheme modules have is a bunch of literals.

That's creative but it's not true.
From: Jens Axel Soegaard
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <47bc9016$0$15891$edfadb0f@dtext01.news.tele.dk>
Kaz Kylheku wrote:
> On Feb 20, 7:41 am, ············@yahoo.com wrote:
>> On Feb 19, 6:28 pm, Kaz Kylheku <········@gmail.com> wrote:
>>
>>> This just doesn't fit into the industrial architecture of Common Lisp.
>>> The reasons why it doesn't fit have a lot to do with why we have cruft
>>> like EVAL-WHEN, LOAD-TIME-VALUE, COMPILE-FILE and all those non-
>>> academic things that uglify textbook examples with irrelevant software
>>> development and deployment concerns.
>> Those irrelevant industrial concerns have long been addressed
>> in Scheme, in a way that overcomes the weaknesses of the
>> Common Lisp cruft you mention.  This is best explained in:
>>
>> http://citeseer.ist.psu.edu/flatt02composable.html,
>> an adaptation of which has been incorporated into R6RS.
> 
> You mean that paltry material in section 7?
> 
> Notice how it restricts exported variables: they must be immutable.
> Implicitly exported variables are also immutable.

That's a choice and to some degree a color-of-the-bikeshed issue.
The module and syntax system works fine woth both choices.

Why was the choice made? It has at least two benefits:

   - Outside modules can't destroy internal invariants
   - Allows efficient seperate compiling
       In depth explanation:
         Due to call/cc a standard transformation is to box
         all variables. This is hurts the efficiency of
         variable references, but luckily it is only neccessary
         to box assigned-to variables. In order to determine
         which variables are assignable without the restriction,
         you need to do whole-program compilation. Hence
         the restriction was put in place.

Besides you just provide a settter:

(module a mzscheme
   (provide my-var my-set)

   (define my-var 42)
   (define (my-set expr)
     (set! my-var expr)))

(module b mzscheme
   (require a)
   (display my-var)
   (newline)
   (my-set 3.14)
   (display my-var)
   (newline))

 > (require b)
42
3.14


> If a macro from some module generates an expansion that refers to one
> of those module's private variables, that variable becomes implicitly
> exported. And then, assignment to it is forbidden.
> 
> But ``immutable variable'' is an oxymoron; the correct name for such a
> thing is ``literal constant''.
> 
> Literal constants trivially solve referential problems because they
> can be reduced to their values and fully inlined.
> 
> This is weak. But R7RS will fix that, undoubtedly.

I hope not.

-- 
Jens Axel S�gaard
From: Slom
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <abc092e6-a11f-4d15-955a-889d78807bc3@d21g2000prf.googlegroups.com>
> The problem with this is that it's dumb for a macro expansion to
> capture material from the site of the macro definition. It continues
> to be dumb even after you've solved the minor technical problems
> (unraveling your symbolic references so that they don't conflict by
> some trivial renaming).
>
> This just doesn't fit into the industrial architecture of Common Lisp.
> The reasons why it doesn't fit have a lot to do with why we have cruft
> like EVAL-WHEN, LOAD-TIME-VALUE, COMPILE-FILE and all those non-
> academic things that uglify textbook examples with irrelevant software
> development and deployment concerns.

translated:
I dont need your screwdriver, I have a *Big Hammer* allready ;)

Slom
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <622p33F21i4l4U1@mid.individual.net>
Kaz Kylheku wrote:
> On Feb 16, 5:43 pm, Pascal Costanza <····@p-cos.net> wrote:
>> John Thingstad wrote:
>>> P� Sat, 16 Feb 2008 21:32:26 +0100, skrev <············@yahoo.com>:
>>>> is simply being out of date.  Scheme macros are considered by Schemers
>>>> to be more robust than Lisp defmacros, given the referential
>>>> transparency guarantees of Scheme macros, although I know Lispers tend
>>>> not to care
>>>> about this issue.
>>> We care. We just take care of it through protocol of writing.
>>> gensym is a bit lightweight. With the help of a couple of macroes named
>>> 'with-unique-names' and 'rebinding' it is fairly easy to write
>>> referentially transparent code. Rebinding for rebinding input variables
>>> so they are evaluated before use. with-unique-values for introducing new
>>> variables.
>> [...]
>>
>>> This seems to cover most cases.
>> No, that's not enough. What you list here solves the problems of
>> unintended variable capture, and order and number of evaluations.
>> Referential transparency is something else, though.
>>
>> Consider:
>>
>> (let ((x 42))
>>    (macrolet ((foo () 'x))
>>      (let ((x 4711))
>>        (foo))))
> 
> 
> The problem with this is that it's dumb for a macro expansion to
> capture material from the site of the macro definition. It continues
> to be dumb even after you've solved the minor technical problems
> (unraveling your symbolic references so that they don't conflict by
> some trivial renaming).

Huh? It's rare that macros expand into uses of definitions of the core 
language alone. You typically also expand into uses of your own 
definitions as well. (That's actually the recommended approach to macro 
programming: Write your libraries as functional abstractions, and then 
provide macros as a preferably thin layer on top of that.)

So you have to ensure that such references to your own definitions mean 
what they are supposed to mean.

> Under this separated compilation model, how the heck can the macro
> expansions in M-use.fasl refer to a lexical environment which only
> exists when M-define.fasl is loaded and stuff inside it is evaluated?

Under the assumption that modules are first-class runtime entities, once 
you export a macro from a module that expands into a use of some 
variable/function from that same module, such variables/functions must 
of course be implicitly or explicitly be exported as well. This has 
nothing to do with lexical environments per se, only with references to 
names in modules. (Modules are, of course, lexical environments, but 
macros don't directly refer to such environments - they can't.)


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Kaz Kylheku
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <37147e58-29d9-4f9a-92db-bbd19dc56e38@q70g2000hsb.googlegroups.com>
On Feb 16, 5:43 pm, Pascal Costanza <····@p-cos.net> wrote:
> If Common Lisp had a module system instead of a package system, and if
> Common Lisp were a Lisp-1 instead of a Lisp-2,

But CL has a module system /and/ a package system. Without the package
system, the module system would still be the right way to handle
macros: DEFVAR/DEFPARAMETER for variables belonging to the macro
implementation, DEFUN for functions called by macro expansions. Only,
you'd merely have to ensure that these are uniquely named without the
help of a package system. The qualifier could go into the symbol name
as a prefix. Big deal!

Not having a package system wouldn't be a sufficient reason to start
doing dumb things, like capturing random instances of lexical
environments inside macro modules and spreading these throughout the
image.

In real programs, references through global symbols are superior to
lexical references for the purposes of making a huge program out of
little pieces.
From: Ron Garret
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <rNOSPAMon-ED5188.16155619022008@news.gha.chartermi.net>
In article 
<····································@q70g2000hsb.googlegroups.com>,
 Kaz Kylheku <········@gmail.com> wrote:

> On Feb 16, 5:43�pm, Pascal Costanza <····@p-cos.net> wrote:
> > If Common Lisp had a module system instead of a package system, and if
> > Common Lisp were a Lisp-1 instead of a Lisp-2,
> 
> But CL has a module system /and/ a package system. Without the package
> system, the module system would still be the right way to handle
> macros: DEFVAR/DEFPARAMETER for variables belonging to the macro
> implementation, DEFUN for functions called by macro expansions. Only,
> you'd merely have to ensure that these are uniquely named without the
> help of a package system. The qualifier could go into the symbol name
> as a prefix. Big deal!
> 
> Not having a package system wouldn't be a sufficient reason to start
> doing dumb things, like capturing random instances of lexical
> environments inside macro modules and spreading these throughout the
> image.
> 
> In real programs, references through global symbols are superior to
> lexical references for the purposes of making a huge program out of
> little pieces.

I don't understand.  Why should:


(let ((x ...))
  (defmacro ... () (foo x)))


be any different from:


(let ((x ...))
  (defun f () (foo x)))

(defmacro ... () (f ...))


particularly in light of the fact that one can do e.g.:


(progn
  '#1=#:f      ; Or #:|| to really drive the point home
  (let (...)
    (defun #1# () (foo x)))
  (defmacro ... () (#1# ...)))


rg
From: Kent M Pitman
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <uzltwv0t6.fsf@nhplace.com>
[ comp.lang.lisp only; http://www.nhplace.com/kent/PFAQ/cross-posting.html ]

Ron Garret <·········@flownet.com> writes:

> I don't understand.  Why should:
> 
> 
> (let ((x ...))
>   (defmacro ... () (foo x)))
> 
> be any different from:
> 
> (let ((x ...))
>   (defun f () (foo x)))
> 
> (defmacro ... () (f ...))

Because the binding has to happen at a known time so the init form
happens at a known time.

One could make a form that has a known time, but one would have to 
define the semantics to accommodate ... it doesn't just happen for
free.  And the reason they're not defined is mostly that no one was
happy with the various semantics that were discussed.

So, for example, the real issue [and the reason the operator is not
defined this way] is expressed by looking at concrete use cases.  A
typical one might be:

When would

(let ((x (print ''a)))
  (defmacro foo () x)
  (foo))

print (QUOTE A)?  At compile time? At load time? Both?

Moreover, why would the compiler know to expand (foo) at all since the
definition of FOO as a macro would not be installed until runtime, if
it were to follow what DEFUN does.

> particularly in light of the fact that one can do e.g.:
> 
> (progn
>   '#1=#:f      ; Or #:|| to really drive the point home
>   (let (...)
>     (defun #1# () (foo x)))
>   (defmacro ... () (#1# ...)))

I'm going to assume you wrote:

> (progn
>   '#1=#:f      ; Or #:|| to really drive the point home
>   (let ((x ...))
>     (defun #1# () (foo x)))
>   (defmacro g () (#1# ...)))

so I can refer to the parts more easily.

I personally would not rely on that macro to work so I don't
know if your claim is correct.

It will work in the same file, but if you ever later do any
macroexpansion of G which you don't then immediately compile but
instead externalize (e.g., by print) to a file for later compilation,
you'll find that when it reloads, the use of the gensym won't be
repatriated correctly.  Not that that's your point.  It's just a
lurking bug in your program that will survive a long time before being
noticed.

But as to the part about the binding of x, what you should know is
that it's permissible for calls to (g) to warn that f is undefined,
since it doesn't take on a value until runtime [when the defun is
executed], and the compiler doesn't notice that your #:F function (in
the cases where it works at all [1]) has a definition.

[1] = not to be confused with the cases where it doesn't work because
in fact it never gets a definition.

Lisp used to have COMPILER-LET, and no one liked it.  But it was much
closer to the semantics you want. In mixed compiled and interpreted
code with special and lexical bindings all about, it created cases
where it was very hard to debug.  So we removed it.
From: Ron Garret
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <rNOSPAMon-FA4DC3.22104619022008@news.gha.chartermi.net>
In article <·············@nhplace.com>,
 Kent M Pitman <······@nhplace.com> wrote:

> [ comp.lang.lisp only; http://www.nhplace.com/kent/PFAQ/cross-posting.html ]
> 
> Ron Garret <·········@flownet.com> writes:
> 
> > I don't understand.  Why should:
> > 
> > 
> > (let ((x ...))
> >   (defmacro ... () (foo x)))
> > 
> > be any different from:
> > 
> > (let ((x ...))
> >   (defun f () (foo x)))
> > 
> > (defmacro ... () (f ...))
> 
> Because the binding has to happen at a known time so the init form
> happens at a known time.

Huh?!?

> So, for example, the real issue [and the reason the operator is not
> defined this way]

But it IS defined this way!  The spec says of DEFMACRO:

"Defines name as a macro by associating a macro function with that name
 in the global environment. The macro function is defined in the same
                                               ^^^^^^^^^^^^^^^^^^^^^^
 lexical environment in which the defmacro form appears."
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Note that the spec for macrolet says the same thing, but it includes the 
following exception, which is NOT part of the spec for defmacro:

"the consequences are undefined if the local macro definitions reference 
any local variable or function bindings that are visible in that lexical 
environment."

> is expressed by looking at concrete use cases.  A
> typical one might be:
> 
> When would
> 
> (let ((x (print ''a)))
>   (defmacro foo () x)
>   (foo))
> 
> print (QUOTE A)?  At compile time? At load time? Both?

Load time.  Why would you doubt it?  (Note that because the defmacro is 
not a top-level form, the call to FOO will be compiled as a function 
call unless FOO has already been defined as a macro before the file is 
compiled.  And even if FOO has been previously defined as a macro, the 
call to FOO will be compiled as a call to the OLD foo, not the new one.)

> Moreover, why would the compiler know to expand (foo) at all since the
> definition of FOO as a macro would not be installed until runtime, if
> it were to follow what DEFUN does.

Exactly.  I don't see what any of this has to do with anything.  Macros 
call macroexpansion functions, which can be defined in lexical 
environments just like any other function.  Macros are expanded (and 
hence their macroexpansion functions called) at compile time, so it is 
up to the user to insure that those functions exist at compile time 
(through appropriate uses of eval-when most likely).  But I don't see 
any reason why macroexpansion functions should not be able to close over 
lexical variables just like any other function.

rg
From: Ron Garret
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <rNOSPAMon-F76993.22241119022008@news.gha.chartermi.net>
In article <·······························@news.gha.chartermi.net>,
 Ron Garret <·········@flownet.com> wrote:

> Note that the spec for macrolet says the same thing, but it includes the 
> following exception, which is NOT part of the spec for defmacro:
> 
> "the consequences are undefined if the local macro definitions reference 
> any local variable or function bindings that are visible in that lexical 
> environment."

And here's why:

(flet ((f (x) `(cons ',x ',x)))
  (setf (symbol-function 'zoop) #'f)
  (print (symbol-function 'zoop))
  (macrolet ((m (x) (zoop x)))
    (m snoz)))

If you try to run this (well, to be more precise, if you try to compile 
it -- which in CCL amounts to the same thing) then nothing gets printed, 
and you get an error that ZOOP is undefined, which happens when it tries 
to macroexpand (m snoz).

OK, some of this is starting to make sense.

Bummer, hygiene now makes LESS sense to me than it did before.  :-(

rg
From: Kent M Pitman
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <uve4jvgew.fsf@nhplace.com>
Ron Garret <·········@flownet.com> writes:

> In article <·············@nhplace.com>,
>  Kent M Pitman <······@nhplace.com> wrote:
> 
> > [ comp.lang.lisp only; http://www.nhplace.com/kent/PFAQ/cross-posting.html ]
> > 
> > Ron Garret <·········@flownet.com> writes:
> > 
> > > I don't understand.  Why should:
> > > 
> > > 
> > > (let ((x ...))
> > >   (defmacro ... () (foo x)))
> > > 
> > > be any different from:
> > > 
> > > (let ((x ...))
> > >   (defun f () (foo x)))
> > > 
> > > (defmacro ... () (f ...))
> > 
> > Because the binding has to happen at a known time so the init form
> > happens at a known time.
> 
> Huh?!?

See the discussion of the ''a example below.  Note that the semantics you
choose for this needs to be the same that works for other situations--it
can't just support this one example, and not generalize to the language
as a whole.
 
> > So, for example, the real issue [and the reason the operator is not
> > defined this way]
> 
> But it IS defined this way!  The spec says of DEFMACRO:
> 
> "Defines name as a macro by associating a macro function with that name
>  in the global environment. The macro function is defined in the same
>                                                ^^^^^^^^^^^^^^^^^^^^^^
>  lexical environment in which the defmacro form appears."
>  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Because of the restriction you note immediately below here, I think
this means the body of the macro is itself processed in a lexical
environment that sees containing macrolets and symbol-macrolets.  I
agree the wording could have been more clear, but I don't know that
the wording can be taken to mean much else by someone charged with
working through the complete set of consequences consistently.

> Note that the spec for macrolet says the same thing, but it includes
> the following exception, which is NOT part of the spec for defmacro:
> 
> "the consequences are undefined if the local macro definitions
> reference any local variable or function bindings that are visible
> in that lexical environment."

Actually, might be effectively a bug in the spec since it really
cannot work if you reference any block or tag either.

The Lisp1/Lisp2 paper notwithstanding, CL is really a Lisp4 (although
the other two namespaces, block and tag, have so few operations
defined on them that they are rarely mentioned).

> > is expressed by looking at concrete use cases.  A
> > typical one might be:
> > 
> > When would
> > 
> > (let ((x (print ''a)))
> >   (defmacro foo () x)
> >   (foo))
> > 
> > print (QUOTE A)?  At compile time? At load time? Both?
> 
> Load time.  Why would you doubt it?

Because you can't do the macro expansion without the value of x.
And you can't know the value of x without evaluating the print.
But the value of x is needed at compile time, since you have to
expand foo to compile it.  It's even worse if you do:

 (progn (print ''b)
        (let ((x (print ''a)))
          ;; Not permitted in CL
          (defmacro foo () x)
          (foo)))

and ask if you run this interpreted in what order the PRINT would
occur.

> (Note that because the defmacro is not a top-level form, the call to
> FOO will be compiled as a function call unless FOO has already been
> defined as a macro before the file is compiled.  And even if FOO has
> been previously defined as a macro, the call to FOO will be compiled
> as a call to the OLD foo, not the new one.)

Then, at minimum, you won't be able to use FOO as a macro right after
its definition.  We thought that would confuse people.

> > Moreover, why would the compiler know to expand (foo) at all since
> > the definition of FOO as a macro would not be installed until
> > runtime, if it were to follow what DEFUN does.
>
> Exactly.  I don't see what any of this has to do with anything.

Well, it makes LET be a kind of secret DELAY operator for defmacro.
We thought that would be confusing.

> Macros call macroexpansion functions, which can be defined in
> lexical environments just like any other function.  Macros are
> expanded (and hence their macroexpansion functions called) at
> compile time, so it is up to the user to insure that those functions
> exist at compile time (through appropriate uses of eval-when most
> likely).  But I don't see any reason why macroexpansion functions
> should not be able to close over lexical variables just like any
> other function.

Let's be clear.  You are wanting a functionality, and are using the
fact that the present semantics doesn't allow the functionality as a
way of claiming that we have argued the semantics is not possible.

The truth is, though, that the problem isn't the semantics per se.  A
language is a decision tree full of choice points, where each choice
takes you to a different universe where the particular choice is
taken.  The only way to make all possible choices is to have really a
lot of operators (and even then some such universes are nonsensical).

We could have had more kinds of LET.  We used to have COMPILER-LET and
didn't like it.

We could have had a kind of this-is-a-LET-but-if-you-put-a-DEFMACRO-
in-it-it-will-morph-secretly-into-COMPILER-LET LET.  But we didn't even
try that.  That, however, is not a statement that we couldn't have.
At the time, it just didn't seem like a good idea, or not a good enough
idea, or an idea we had time for.

When things happen, they happen for a reason.  When things don't,
there can be many reasons, or no reason.  So it's risky to posit a
reason for doing something and then claim that the reason something
didn't happen was that someone disagreed with your reason.  You might
think the public should invest money in education or in health care or
fixing climate change, and you might think the fact that they don't is
a statement of their belief that such investment won't work.  And
there are people who don't think such investment doesn't work.  But
there are also people who are just broke or have other things to do.

One further thing we don't want to conclude is that because we want a
particular thing at a particular time, and we're not getting it, we
should just assume it's already there and argue that the semantics of
what's there should just extend to that.

DEFMACRO and LET can only have one semantics at a time.  The semantics
you want is different than what is there now.  That means at least one
additional operator or language feature, but in any case, one extra
bit of information is needed.  To that end, I refer you to 
"Pitman's Two-Bit Rule", which I have always intended to cover cases
like this...

 http://www.nhplace.com/kent/PS/EQUAL.html#two-bit_rule
From: Ron Garret
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <rNOSPAMon-9DF960.09273720022008@news.gha.chartermi.net>
In article <·············@nhplace.com>,
 Kent M Pitman <······@nhplace.com> wrote:

> > Note that the spec for macrolet says the same thing, but it includes
> > the following exception, which is NOT part of the spec for defmacro:
> > 
> > "the consequences are undefined if the local macro definitions
> > reference any local variable or function bindings that are visible
> > in that lexical environment."
> 
> Actually, might be effectively a bug in the spec since it really
> cannot work if you reference any block or tag either.

What is the bug?  The fact that blocks and tags are not mentioned, or 
that this exception is given for macrolet but not defmacro?  (BTW, I 
thought tags were part of the dynamic environment, not the lexical 
environment.)

> > > is expressed by looking at concrete use cases.  A
> > > typical one might be:
> > > 
> > > When would
> > > 
> > > (let ((x (print ''a)))
> > >   (defmacro foo () x)
> > >   (foo))
> > > 
> > > print (QUOTE A)?  At compile time? At load time? Both?
> > 
> > Load time.  Why would you doubt it?
> 
> Because you can't do the macro expansion without the value of x.
> And you can't know the value of x without evaluating the print.
> But the value of x is needed at compile time, since you have to
> expand foo to compile it.

No, you don't.  The defmacro is not a top-level form, and so it does not 
get executed at compile time, and the call to FOO gets compiled as 
whatever FOO was defined as before (most likely an call to an undefined 
function).  See section 3.2.3.1.1 of the spec.

I explained this before:

> > (Note that because the defmacro is not a top-level form, the call to
> > FOO will be compiled as a function call unless FOO has already been
> > defined as a macro before the file is compiled.  And even if FOO has
> > been previously defined as a macro, the call to FOO will be compiled
> > as a call to the OLD foo, not the new one.)
> 
> Then, at minimum, you won't be able to use FOO as a macro right after
> its definition.  We thought that would confuse people.

That's right.  You can't.  And it does.

> > > Moreover, why would the compiler know to expand (foo) at all since
> > > the definition of FOO as a macro would not be installed until
> > > runtime, if it were to follow what DEFUN does.
> >
> > Exactly.  I don't see what any of this has to do with anything.
> 
> Well, it makes LET be a kind of secret DELAY operator for defmacro.
> We thought that would be confusing.

That's right.  It is.

BTW, a top-level LET is a "secret delay" operator for DEFUN too, and 
everything else that closes over the lexical environment.  If this 
doesn't work:

(let ((x ...))
  (defmacro foo (...) (... x ...)))

because you don't know what X is at compile time then this can't work 
either:

(let ((x ...))
  (defun my-macroexpander (...) ... x ...))

(defmacro foo (...) (my-macroexpander ...))

for exactly the same reason.

This becomes self-evident if you expand a top-level LET into its 
constituent lambdaas:

(let ((x initval))
  (defwhatever foo .... x ...))

expands into:

((lambda (x) (some-side-effecting-frob foo (lambda (...) ...)) initval)

which you can compile just fine without computing initval.  But you 
can't run it without computing initval, and until you run it, the 
side-effected value of FOO is not available.  No big surprise there.  It 
has nothing to do with whether or not lexical references within a 
defmacro make semantic sense or not.  They clearly do.

Furthermore, it seems to me that the whole issue completely evaporates 
if you just wrap the top-level let inside an appropriate eval-when.

> > Macros call macroexpansion functions, which can be defined in
> > lexical environments just like any other function.  Macros are
> > expanded (and hence their macroexpansion functions called) at
> > compile time, so it is up to the user to insure that those functions
> > exist at compile time (through appropriate uses of eval-when most
> > likely).  But I don't see any reason why macroexpansion functions
> > should not be able to close over lexical variables just like any
> > other function.
> 
> Let's be clear.  You are wanting a functionality, and are using the
> fact that the present semantics doesn't allow the functionality as a
> way of claiming that we have argued the semantics is not possible.

No, I don't care about the functionality one way or another.  What I 
care about (at least for the moment) is understanding why things are the 
way they are in light of what the spec actually says.  I don't care 
*that* it doesn't work, I want to understand *why* it doesn't work.  It 
still seems to me that, according to the spec, it should.

rg
From: Kent M Pitman
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <u1w767umx.fsf@nhplace.com>
Ron Garret <·········@flownet.com> writes:

> In article <·············@nhplace.com>,
>  Kent M Pitman <······@nhplace.com> wrote:
> 
> > > Note that the spec for macrolet says the same thing, but it includes
> > > the following exception, which is NOT part of the spec for defmacro:
> > > 
> > > "the consequences are undefined if the local macro definitions
> > > reference any local variable or function bindings that are visible
> > > in that lexical environment."
> > 
> > Actually, might be effectively a bug in the spec since it really
> > cannot work if you reference any block or tag either.
> 
> What is the bug?  The fact that blocks and tags are not mentioned, or 
> that this exception is given for macrolet but not defmacro?  (BTW, I 
> thought tags were part of the dynamic environment, not the lexical 
> environment.)

Ok, let's back up because I said a couple of things without checking
with the spec and ended up saying some incorrect things and I want to
correct what I said before I confuse anyone further.  I'll have to go
back and re-analyze what I responded to see where I confused matters,
but for now let me just say some remarks that basically correct what I
said wrong.

And also, I apologize for doubting you here.

I'll come back to the remark above about consequences undefined.  That
is easier to understand in context after I get to the other part.

It's easiest to understand both DEFUN and DEFMACRO if you think of them
as being defined approximately thus:

 (defmacro defun (name bvl &body decls-doc-forms) ;ONLY APPROXIMATE!
   (destructuring-bind (decls doc forms)
       (parse-definition-body decls-doc-forms)
     `(progn 
        (eval-when (:execute :load-toplevel)
          (setf (symbol-function ',name) #'(lambda ,bvl ,@decls ,@forms))
          (setf (documentation ',name 'function) ,doc))
        (eval-when (:compile-toplevel)
          ;; Various implementation-dependent things compiler notices if form
          ;; is at toplevel...
          (tell-compiler-function-definition-seen ',function ',bvl ',decls)
          (tell-editor-how-to-indent ',function ',bvl)
          ;;...etc.
        ',name))))

The situation is similar for defmacro (albeit metacircular):

 (defmacro defmacro (name bvl &body decls-doc-forms) ;ONLY APPROXIMATE!
   (destructuring-bind (decls doc forms)
       (parse-definition-body decls-doc-forms)
     (let ((form (gensym "FORM")) 
           (env (or (cadr (member '&environment bvl))
                    (gensym "ENV")))
           (macro-definition
             `#'(lambda (,form ,env)
                  (declare (ignorable ,env))
                  (destructuring-bind ,bvl ,form ,@decls ,@forms))))
      `(progn 
        (eval-when (:execute :load-toplevel)
          (setf (macro-function ',name) ,macro-definition)
          (setf (documentation ',name 'function) ,doc))
        (eval-when (:compile-toplevel)
          ;; macro definition happens at compile-time too!
          (tell-compiler-about-macro ',name ,macro-definition)
          ;; Various implementation-dependent things compiler notices if form
          ;; is at toplevel...
          (tell-editor-how-to-indent ',function ',bvl)
          ;;...etc.
        ',name)))))

There are probably flaws in the above.  I just made it up as a sketch
to illustrate that there are things that go on when you execute the
definition, and things that go on at compile time.  So when you embed
one of these, it does capture the lexical environment, and it doesn't
execute until runtime.

So to undersand what these do when in a LET, you notice that this makes
them not at toplevel, and it means the :execute clause is done.  At
toplevel, the :compile-toplevel stuff is done when compiling, and then
the :load-toplevel stuff is done when loading.

So you can see that's why here:

> > > > (let ((x (print ''a)))
> > > >   (defmacro foo () x)
> > > >   (foo))

there is an issue because (foo) is in a context where the definition inline
will be

 (let ((x (print ''a)))
   (progn
     (eval-when (:execute :load-toplevel)
       (setf (macro-function 'foo) ...) ...)
     (eval-when (:compile-toplevel)
       (tell-compiler-about-macro 'foo ...))
     'foo)
   (foo))

is being done, and since you're not at toplevel, this as if you did:

(let ((x (print ''a)))
   (progn
     (progn
       (setf (macro-function 'foo) ...) ... nil)
     nil
     'foo)
   (foo))

which you can reduce to:

 (let ((x (print ''a)))
   (setf (macro-function 'foo) ...)
   (foo))

and it should be easy to see that (foo) is not going to win because its
macro definition is not set early enough.

> > Because you can't do the macro expansion without the value of x.
> > And you can't know the value of x without evaluating the print.
> > But the value of x is needed at compile time, since you have to
> > expand foo to compile it.
> 
> No, you don't.  The defmacro is not a top-level form, and so it does not 
> get executed at compile time, and the call to FOO gets compiled as 
> whatever FOO was defined as before (most likely an call to an undefined 
> function).  See section 3.2.3.1.1 of the spec.

Yes, I think that's right and that I was wrong.

> I explained this before:
> 
> > > (Note that because the defmacro is not a top-level form, the call to
> > > FOO will be compiled as a function call unless FOO has already been
> > > defined as a macro before the file is compiled.  And even if FOO has
> > > been previously defined as a macro, the call to FOO will be compiled
> > > as a call to the OLD foo, not the new one.)
> > 
> > Then, at minimum, you won't be able to use FOO as a macro right after
> > its definition.  We thought that would confuse people.
> 
> That's right.  You can't.  And it does.

Yes.

> > > > Moreover, why would the compiler know to expand (foo) at all since
> > > > the definition of FOO as a macro would not be installed until
> > > > runtime, if it were to follow what DEFUN does.
> > >
> > > Exactly.  I don't see what any of this has to do with anything.
> > 
> > Well, it makes LET be a kind of secret DELAY operator for defmacro.
> > We thought that would be confusing.
> 
> That's right.  It is.

Heh.
 
> BTW, a top-level LET is a "secret delay" operator for DEFUN too, and 
> everything else that closes over the lexical environment.  If this 
> doesn't work:
> 
> (let ((x ...))
>   (defmacro foo (...) (... x ...)))
> 

On reflection, I this should work.

What won't work is to use FOO in the same file.  But if you've done the
:execute [e.g., due to immediate evaluation], that works, too.

> because you don't know what X is at compile time then this can't work 
> either:
> 
> (let ((x ...))
>   (defun my-macroexpander (...) ... x ...))
> 
> (defmacro foo (...) (my-macroexpander ...))
> 
> for exactly the same reason.

The problem here is that my-macroexpander isn't available until runtime.
The above will work as long as FOO isn't used in the same file.
It will fail if it is, and it needs
 (eval-when (:execute :load-toplevel :compile-toplevel)
   ...)
around the LET if you want to use the definition of my-macroexpander later
in the same file that the defmacro foo occurs.

> This becomes self-evident if you expand a top-level LET into its 
> constituent lambdaas:
> 
> (let ((x initval))
>   (defwhatever foo .... x ...))
> 
> expands into:
> 
> ((lambda (x) (some-side-effecting-frob foo (lambda (...) ...)) initval)

You'll do better to understand it in terms of eval-when.  That may be the
missing piece that helps you understand it.

Note, btw, that compiler version of the macro would have no access to the
lexical variables, so would be serious trouble in the case of a closure,
but since the :compile-toplevel will not activate in that case, it's a
non-issue.

Note further, finally coming back to the deferred topic about local macros,
that a local macro NEVER has a load time--it is always processed at what
amounts to compile time in the pre-evaluation environment, so it must be
possible to capture and use it immediately.

That is,
 
 (defun foo (x)
   (macrolet ((bar () x))
     (bar)))

needs to be compiled into

 (setf (symbol-function 'foo)
   (lambda (x) <expansion-of-bar>))

but since x's value isn't known yet when that expansion is done, it's
like using the macro in the same file if it's other than at toplevel...
except there is no eval-when to rescue it in this case. So the situation
of seeing the variables is prohibited.

> [...]
> No, I don't care about the functionality one way or another.  What I 
> care about (at least for the moment) is understanding why things are the 
> way they are in light of what the spec actually says.  I don't care 
> *that* it doesn't work, I want to understand *why* it doesn't work.  It 
> still seems to me that, according to the spec, it should.

Does this kind of analysis make any more sense?  I THINK this is
closer to right.  Though it's late and I might still have made some
mistake somewhere.  At least this time I looked at the spec first,
though.  Handy thing that.  People always expect me to still remember
it, but the truth is that the day I finished writing it, I felt this
gigantic sigh of relief as I realized I could sometimes just look
things up like anyone else and not have to hold all that stuff in my
brain any more...
From: Ron Garret
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <rNOSPAMon-D5BE63.07263621022008@news.gha.chartermi.net>
In article <·············@nhplace.com>,
 Kent M Pitman <······@nhplace.com> wrote:

[ Lots of stuff ]

> Does this kind of analysis make any more sense?

Yes.  Thanks for taking the time to explain it.

rg
From: Kaz Kylheku
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <b595dbf5-8edc-4eeb-82b9-e028bcb3547d@u10g2000prn.googlegroups.com>
On Feb 19, 4:15 pm, Ron Garret <·········@flownet.com> wrote:
> In article
> <····································@q70g2000hsb.googlegroups.com>,
>  Kaz Kylheku <········@gmail.com> wrote:
>
>
>
>
>
> > On Feb 16, 5:43 pm, Pascal Costanza <····@p-cos.net> wrote:
> > > If Common Lisp had a module system instead of a package system, and if
> > > Common Lisp were a Lisp-1 instead of a Lisp-2,
>
> > But CL has a module system /and/ a package system. Without the package
> > system, the module system would still be the right way to handle
> > macros: DEFVAR/DEFPARAMETER for variables belonging to the macro
> > implementation, DEFUN for functions called by macro expansions. Only,
> > you'd merely have to ensure that these are uniquely named without the
> > help of a package system. The qualifier could go into the symbol name
> > as a prefix. Big deal!
>
> > Not having a package system wouldn't be a sufficient reason to start
> > doing dumb things, like capturing random instances of lexical
> > environments inside macro modules and spreading these throughout the
> > image.
>
> > In real programs, references through global symbols are superior to
> > lexical references for the purposes of making a huge program out of
> > little pieces.
>
> I don't understand.  Why should:
>
> (let ((x ...))
>   (defmacro ... () (foo x)))

Uses of this macro don't insert a reference to X into the expansion
site, so it's not pertinent to macro hygiene.

What is inserted into the expansion site is the form that is
calculated by the call (foo x), where x is evaluated within the macro
function at macro-expansion time, using straightforward access to the
surrounding lexical environment.
From: William D Clinger
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <4f7a233f-a5d1-4ff1-b067-153170faa2ad@s13g2000prd.googlegroups.com>
Kaz Kylheku wrote:
> Scheme doesn't address this kind of petty concern because it has no
> model for file compiling, loading or, really, composing a large
> program out of little pieces.

Then Kaz Kylheku wrote:
> The problem with this is that it's dumb for a macro expansion to
> capture material from the site of the macro definition. It continues
> to be dumb even after you've solved the minor technical problems
> (unraveling your symbolic references so that they don't conflict by
> some trivial renaming).

And then Kaz Kylheku wrote:
> This just doesn't fit into the industrial architecture of Common Lisp.
> The reasons why it doesn't fit have a lot to do with why we have cruft
> like EVAL-WHEN, LOAD-TIME-VALUE, COMPILE-FILE and all those non-
> academic things that uglify textbook examples with irrelevant software
> development and deployment concerns.

All of that was posted not only to comp.lang.lisp,
where some readers might take it seriously, but
also to comp.lang.scheme, where many readers have
actual experience with referentially transparent
macros and their use in constructing programs out
of smaller pieces.

Eventually Kaz asked:
> In an actual software development situation, why would anyone /want/ a
> macro expansion to be compiled with lexical references to helper
> material?

Finally, as if to prove he wasn't just pulling our
collective leg, Kaz Kylheku declaimed:
> In real programs, references through global symbols are superior to
> lexical references for the purposes of making a huge program out of
> little pieces.

Will
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <622qfcF21gekcU1@mid.individual.net>
Pascal Costanza wrote:
> John Thingstad wrote:
>> P� Sat, 16 Feb 2008 21:32:26 +0100, skrev <············@yahoo.com>:
>>
>>> is simply being out of date.  Scheme macros are considered by Schemers
>>> to be more robust than Lisp defmacros, given the referential
>>> transparency guarantees of Scheme macros, although I know Lispers 
>>> tend not to care
>>> about this issue.
>>>
>>
>> We care. We just take care of it through protocol of writing.
>> gensym is a bit lightweight. With the help of a couple of macroes 
>> named 'with-unique-names' and 'rebinding' it is fairly easy to write 
>> referentially transparent code. Rebinding for rebinding input 
>> variables so they are evaluated before use. with-unique-values for 
>> introducing new variables.
> [...]
> 
>> This seems to cover most cases.
> 
> No, that's not enough. What you list here solves the problems of 
> unintended variable capture, and order and number of evaluations. 
> Referential transparency is something else, though.
> 
> Consider:
> 
> (let ((x 42))
>   (macrolet ((foo () 'x))
>     (let ((x 4711))
>       (foo))))
> 
> Now assume you're not allowed to change the names of the x variable 
> bindings. In a defmacro-style macro system, there is no way that you can 
> ensure that the code to which foo expands refers to the outer x by just 
> changing the macro definition. Whatever you may try, the outer x will be 
> shadowed by the inner x in the inner expansion of foo.
> 
> Hygienic macro systems solve this issue. The following evaluates to 42:
> 
> (let ((x 42))
>   (let-syntax ((foo (syntax-rules () ((foo) x))))
>     (let ((x 4711))
>       (foo))))

Here is another way to look at this: Traditionally, Lisp dialects had a 
feature that allows you to define functions which don't evaluate their 
arguments, but receive them as unevaluated s-expressions (called fexpr 
or nlambda, or so). Let's assume such functions also receive the lexical 
scope from the call site as a first-class representation. Then you could 
do the following:

(define current-lexical-environment
   (nlambda (exp env) env))

(let ((x 42))
   (let ((foo (nlambda (exp env)
                (eval 'x (current-lexical-environment))))
     (let ((x 4711))
       (foo))))

This will evaluate to 42, since foo evaluates 'x in _its_ current 
lexical environment.

You can actually simplify this without using eval:

(let ((x 42))
   (let ((foo (nlambda (exp env) x)))
     (let ((x 4711))
       (foo))))

In this simple example, you actually don't need a feature like nlambda.

However, typically you want to mix the environments from the definition 
site and the call site:

(define if
   (nlambda (exp env)
     (cond ((eval (car exp) env)
            (eval (cadr exp) env))
           (t (eval (caddr exp) env)))))

This definition ensures that the definitions for 'cond, 'eval and 't are 
looked up at the definition site of 'if (its lexical environment), 
whereas the expressions passed to 'if are looked up at the call site of 
the respective invocation of 'if.

Traditional Lisp-style macro systems only allow you to look up bindings 
at the call site. Hygienic macro systems automatically mix definition 
and call sites for you. (Systems based on renaming or syntactic closures 
allow you to mix definition and call sites manually, like in such a 
hypothetical nlambda feature.)


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: John Thingstad
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <op.t6mstx01ut4oq5@pandora.alfanett.no>
P� Sat, 16 Feb 2008 19:35:46 +0100, skrev <············@yahoo.com>:

> Good grief.
>
> Here is an idiomatic way of expressing that, trivially, in Scheme
> (R6RS).
>
> (define-syntax let
>   (lambda (form)
>     (syntax-case form ()
>       ((_ (b ...) e ...)
>        (with-syntax
>            ((((x v) ...)
>              (map (lambda (b)
>                     (syntax-case b ()
>                       ((x v) (identifier? x) #'(x v))
>                       ((x)   (identifier? x) #'(x '()))
>                       (x     (identifier? x) #'(x '()))))
>                   #'(b ...))))
>          #'((lambda (x ...) e ...) v ...))))))
>

We must have different ideas of trivial..

> One could just as well ask why Schemers themselves like to use
> patterns for macros yet prefer not to use pattern matching for
> function definitions as in ML.

I wonder about that one myself.

--------------
John Thingstad
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <2c539227-053a-411a-868b-5d9693a17f30@q78g2000hsh.googlegroups.com>
On Feb 16, 2:09 pm, "John Thingstad" <·······@online.no> wrote:
> På Sat, 16 Feb 2008 19:35:46 +0100, skrev <············@yahoo.com>:
>
> > Here is an idiomatic way of expressing that, trivially, in Scheme
> > (R6RS).
>
> > (define-syntax let
> >   (lambda (form)
> >     (syntax-case form ()
> >       ((_ (b ...) e ...)
> >        (with-syntax
> >            ((((x v) ...)
> >              (map (lambda (b)
> >                     (syntax-case b ()
> >                       ((x v) (identifier? x) #'(x v))
> >                       ((x)   (identifier? x) #'(x '()))
> >                       (x     (identifier? x) #'(x '()))))
> >                   #'(b ...))))
> >          #'((lambda (x ...) e ...) v ...))))))
>
> We must have different ideas of trivial..

I can assure you that a Scheme programmer
familiar with syntax-case would find this utterly trivial.
I am not sure how this macro might be expressed idiomatically
in Lisp, but probably a Lisper would find the result more
transparent than the above, while I would probably find it much
less trivial.  Again, that is cultural, and it would be silly
to argue that Scheme macros are, therefore, inferior.

> > One could just as well ask why Schemers themselves like to use
> > patterns for macros yet prefer not to use pattern matching for
> > function definitions as in ML.
>
> I wonder about that one myself.

Perhaps because Schemers tend to come from more academic backgrounds
where using a BNF-type notation for syntax comes naturally.
On the other hand, there is no built-in emphasis on algebraic data
types as in ML.

Andre
From: llama
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <-dadne7Q1_0TKyjanZ2dnUVZ8uydnZ2d@saix.net>
<············@yahoo.com> wrote in message 
·········································@u10g2000prn.googlegroups.com...

> and a little quiz:
>
>  (let ((x '(a b c))) ``(,,x ,@,x ,,@x ,@,@x))   => ??
>

Are the last 2 cases (,,@x and ,@,@x) even valid? 
From: ············@yahoo.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <789c3a40-a41f-46e4-b61f-b8042136d25a@s8g2000prg.googlegroups.com>
On Feb 15, 10:56 am, "llama" <····@winamp.com> wrote:
> <············@yahoo.com> wrote in message
>
> >  (let ((x '(a b c))) ``(,,x ,@,x ,,@x ,@,@x))   => ??
>
> Are the last 2 cases (,,@x and ,@,@x) even valid?

They are valid in R6RS Scheme.  I'm not sure about
Common Lisp.
From: Kaz Kylheku
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <a68e4cb3-8d0c-4b8b-9178-82f804177677@u10g2000prn.googlegroups.com>
On Feb 15, 9:02 am, ············@yahoo.com wrote:
> On Feb 15, 10:56 am, "llama" <····@winamp.com> wrote:
>
> > <············@yahoo.com> wrote in message
>
> > >  (let ((x '(a b c))) ``(,,x ,@,x ,,@x ,@,@x))   => ??
>
> > Are the last 2 cases (,,@x and ,@,@x) even valid?
>
> They are valid in R6RS Scheme.

By golly, R5RS doesn't seem define this, only R5R6, which allows
multiple arguments to unquote and unquote-splicing, and contains
nested backquote examples with this type of syntax.

Could it be really be that Scheme had broken backquotes until
recently? I'm rubbing my eyes.

> I'm not sure about Common Lisp.

The distributed-law behavior pops out of the axioms of the semantic
description of backquote expansion in the standard.

Essentially, `(x1 x2 x3 ... . atom)  is defined as being equivalent to
(append [x1] [x2] ... [xn]), where if [xi] looks like ,form it is
interpreted as (list form) and consequently ,,@form means
(list ,@form). I.e. the unquote is defined in terms of LIST, which
handles additional arguments similarly to how the Scheme unquote does,
as of R6RS.   The splicing case is similar. If [xi] looks like ,@form
it is simply reduced to form. So ,@,@form becomes ,@form.

Thus if we expand the inner backquote of this, and leave the outer one
alone, then this:

  ``(,,a ,,@b ,@,@c)

becomes this:

  `(append (list ,a) (list ,@b) ,@c)

Thus if C is bound to a list of forms, they all get spliced into this
append. And so in the next evaluation, each of these forms (except the
last one) must produce lists which are spliced together. Thus the ,@
distributes into the ,@c.
From: llama
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <FMKdnbvvs_okUyjanZ2dnUVZ8tyqnZ2d@saix.net>
<············@yahoo.com> wrote in message 
·········································@s8g2000prg.googlegroups.com...
> On Feb 15, 10:56 am, "llama" <····@winamp.com> wrote:
>> <············@yahoo.com> wrote in message
>>
>> >  (let ((x '(a b c))) ``(,,x ,@,x ,,@x ,@,@x))   => ??
>>
>> Are the last 2 cases (,,@x and ,@,@x) even valid?
>
> They are valid in R6RS Scheme.  I'm not sure about
> Common Lisp.


Sorry, I didnt mean syntactically valid, I meant valid in the sense of the 
computation. So will it produce a result?

What is the behaviour around unquoting/unquotesplicing a spliced list?

I prefer nested quasiquoting with a bit of space between them :) 
From: Alan Crowe
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <864pcaexl2.fsf@cawtech.freeserve.co.uk>
············@yahoo.com writes:

> and a little quiz:
> 
>   (let ((x '(a b c))) ``(,,x ,@,x ,,@x ,@,@x))   => ??
> 

I thought I nearly knew this,

`(,(a b c) ,@(a b c) ,a ,b ,c and err, not sure...

but CMUCL is giving me either


`(,(A B C) ,@(A B C) ,A ,@B) with 19a

or

`(,(A B C) (,@(A B C)) (,A ,@B)) with 19c

while

SBCL says `(,(A B C) ,@(A B C) ,A ,B ,C ,@A ,@B ,@C)

which is convincing

and CLISP says

`(,(A B C) ,@(A B C) (SYSTEM::UNQUOTE A B C) ,@'(SYSTEM::UNQUOTE A B C))

so I'm wondering if there is a bug in CMUCL.

Alan Crowe
Edinburgh
Scotland
From: Kaz Kylheku
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <cb618f35-df1b-4cb4-9f4d-f6e005b9a71e@d21g2000prf.googlegroups.com>
On Feb 15, 1:09 pm, Alan Crowe <····@cawtech.freeserve.co.uk> wrote:
> ············@yahoo.com writes:
> > and a little quiz:
>
> >   (let ((x '(a b c))) ``(,,x ,@,x ,,@x ,@,@x))   => ??
>
> and CLISP says
>
> `(,(A B C) ,@(A B C) (SYSTEM::UNQUOTE A B C) ,@'(SYSTEM::UNQUOTE A B C))

Wow, how old is your CLISP? That looks suspiciously like the old
backquote implementation that was replaced some five years ago.

Now I'm a bit out of date myself here with 2.38, but I get:

[1]> (let ((x '(a b c))) ``(,,x ,@,x ,,@x ,@,@x))
(CONS (A B C) (APPEND (A B C) (LIST* A B C (APPEND A B C))))

It's not as pretty an answer as SBCL's, but right.
From: Kent M Pitman
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <uhcg9mxko.fsf@nhplace.com>
Kaz Kylheku <········@gmail.com> writes:

> On Feb 15, 1:09 pm, Alan Crowe <····@cawtech.freeserve.co.uk> wrote:
> > ············@yahoo.com writes:
> > > and a little quiz:
> >
> > >   (let ((x '(a b c))) ``(,,x ,@,x ,,@x ,@,@x))   => ??
> >
> > and CLISP says
> >
> > `(,(A B C) ,@(A B C) (SYSTEM::UNQUOTE A B C) ,@'(SYSTEM::UNQUOTE A B C))
> 
> Wow, how old is your CLISP? That looks suspiciously like the old
> backquote implementation that was replaced some five years ago.
> 
> Now I'm a bit out of date myself here with 2.38, but I get:
> 
> [1]> (let ((x '(a b c))) ``(,,x ,@,x ,,@x ,@,@x))
> (CONS (A B C) (APPEND (A B C) (LIST* A B C (APPEND A B C))))
> 
> It's not as pretty an answer as SBCL's, but right.

Just eyeballing it, I expected:

 (let ((a '(a1 a2 a3))
       (b '(b1 b2 b3))
       (c '(c1 c2 c3)))
   (flet ((a (&rest foo) `(a-fun ,foo))
          (b (&rest foo) `(b-fun ,foo))
          (c (&rest foo) `(c-fun ,foo)))
     (macrolet ((show-it ()
                  (let ((x '(a b c))) ``(,,x ,@,x ,,@x ,@,@x))))
       (show-it))))
 `(,(a b c) ,@(a b c) ,a ,b ,c ,@a ,@b ,@c)

to return the same as:

 (let ((a '(a1 a2 a3))
       (b '(b1 b2 b3))
       (c '(c1 c2 c3)))
   (flet ((a (&rest foo) `(a-fun ,foo))
          (b (&rest foo) `(b-fun ,foo))
          (c (&rest foo) `(c-fun ,foo)))
     (macrolet ((show-it ()
                  '(append (list (a b c))
                           (a b c)
                           (list a b c)
                           a b c)))
        (show-it))))

... and it seems to do that.

No, I don't recommend using these idioms all the time.  But that's not
how they come up.  They happen gradually.

Complicated syntax isn't there because you're always supposed to use it.
It's there so that if you drift into it gradually you won't suddenly fall
off a cliff and have to suddenly be forced to use a different syntax.

You can make very long sentences in English (and other natural
languages), too, even though style guides will tell you only to use a
subset of what you theoretically can do.
From: Alan Crowe
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <86ejbdw7vb.fsf@cawtech.freeserve.co.uk>
Kaz Kylheku <········@gmail.com> writes:

> On Feb 15, 1:09 pm, Alan Crowe <····@cawtech.freeserve.co.uk> wrote:
> > ············@yahoo.com writes:
> > > and a little quiz:
> >
> > >   (let ((x '(a b c))) ``(,,x ,@,x ,,@x ,@,@x))   => ??
> >
> > and CLISP says
> >
> > `(,(A B C) ,@(A B C) (SYSTEM::UNQUOTE A B C) ,@'(SYSTEM::UNQUOTE A B C))
> 
> Wow, how old is your CLISP? That looks suspiciously like the old
> backquote implementation that was replaced some five years ago.
> 

[1]> (lisp-implementation-version) 
"2000-03-06 (March 2000)"

Yes, I've fallen behind a little. I think I mentioned
recently that I've not been well.

Alan Crowe
Edinburgh
Scotland
From: Kaz Kylheku
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <9305820f-3d67-422a-8091-494f4d9224c2@p73g2000hsd.googlegroups.com>
On Feb 15, 5:15 pm, Kaz Kylheku <········@gmail.com> wrote:
> On Feb 15, 1:09 pm, Alan Crowe <····@cawtech.freeserve.co.uk> wrote:
>
> > ············@yahoo.com writes:
> > > and a little quiz:
>
> > >   (let ((x '(a b c))) ``(,,x ,@,x ,,@x ,@,@x))   => ??
>
> > and CLISP says
>
> > `(,(A B C) ,@(A B C) (SYSTEM::UNQUOTE A B C) ,@'(SYSTEM::UNQUOTE A B C))
>
> Wow, how old is your CLISP? That looks suspiciously like the old
> backquote implementation that was replaced some five years ago.
>
> Now I'm a bit out of date myself here with 2.38, but I get:
>
> [1]> (let ((x '(a b c))) ``(,,x ,@,x ,,@x ,@,@x))
> (CONS (A B C) (APPEND (A B C) (LIST* A B C (APPEND A B C))))
>
> It's not as pretty an answer as SBCL's, but right.

I just did some hacking on CLISP's backquote again, after five years.
Now in my sandbox, CLISP's output for the above test case is also:

`(,(A B C) ,@(A B C) ,A ,B ,C ,@A ,@B ,@C)

(The implementation doesn't pass the backquote test cases in ``make
check'' yet, so I can't submit it. Some of them have to be changed,
since they check for a specific macro-expansion out of a nested
backquote. Some of them catch some bad optimization, though: my hacked
backquote leaves some extra APPEND calls that can disappear, so that's
my remaining issue).

Five years ago I thought it was cool for backquote to reduce
everything to backquote-free code, including all nestings. But I see
that there is value in being able to debug nested backquotes, with the
help of an implementation which intersperses expansion rounds with
evaluation rounds, and works outside-in.

If you have a macro-defining macro with a double backquote, and you
macroexpand-it to see what is going on, it's nice to see the result
pop out as a macro with a nice backquote, like what you would have
written if you didn't have the macro-defining macro. It's not that
helpful to see a macro terminated an expression that is an
incomprehensible pudding of LIST*, APPEND, CONS, ...
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <61j04iF1vccqrU1@mid.individual.net>
Alex Shinn wrote:
>>>>>> "Ken" == Ken Tilton <···········@optonline.net> writes:
> 
>     [ ... why syntax-rules? ... ]
> 
>     Ken> 4. Other _____________________
> 
> I won't presume as to the R5RS editors original reasons, but
> I suspect it has to do with the fact that SYNTAX-RULES was
> and remains the simplest and most natural macro system for
> describing all of the derived syntax in R5RS itself.

I don't think that syntax rules. ;)


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: William D Clinger
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <ba935f9d-4475-477b-9d4b-d2c2d9728d6b@q77g2000hsh.googlegroups.com>
When you get right down to it, the real reason we
added syntax-case to Scheme was #' envy.

Will
From: Abdulaziz Ghuloum
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fp2mfb$a56$1@aioe.org>
Ken Tilton wrote:
> What was wrong with treating the source as an ordinary tree 
> of data and just whinging it about with Scheme itself to 
> produce the output?

There is nothing really wrong with that.  However, permitting
alternative representation of the source opens up the opportunity
for the implementation to do more.  An example of that is having
the implementation report contextual information about where
syntax errors occurred and to keep that information around so
that debuggers and profilers show information in the context of
the original source code, not the expanded code.

Here is a small example to illustrate the first case.

$ cat test.ss
#!/usr/bin/env scheme-script
(import (rnrs))

(define-syntax foo
   (syntax-rules ()
     [(_ a b c) (let ([a b]) c)]))

(define-syntax bar
   (syntax-rules ()
     [(_ a b c) (foo b a c)]))

(foo a 12 (bar b 17 (list a b)))


$ ikarus --r6rs-script test.ss
Unhandled exception:
  Condition components:
    1. &who: let
    2. &message: "not an identifier"
    3. &syntax:
        form: (let ((17 b)) (list a b))
        subform: 17
    4. &trace: #<syntax (let ((17 b)) (list a b))>
    5. &trace: #<syntax (foo 17 b (list a b))>
    6. &trace: #<syntax (bar b 17 (list a b)) [byte 200 of test.ss]>


As you can see, it shows the original file name and position in
terms of the user's original source code.  It also shows the
macro expansion steps that contributed to producing that error.
The outer call to foo is not shown because it expanded properly.
The inner call to bar expanded to a call to foo, which expanded
to a let, which caught the error.  The transformation steps are
shown in the trace output.

Some may think that this advantage does not outweigh dropping
the raw s-expression form.  But others value things differently.
These are just different points in the design space.  Neither
is "wrong": they just cater to different needs.

Aziz,,,
From: ·················@gmail.com
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <8f1ef252-58fb-4de4-8ac1-58f5111f2064@d4g2000prg.googlegroups.com>
On Feb 15, 1:30 am, Abdulaziz Ghuloum <········@cee.ess.indiana.edu>
wrote:list a b)))
>
> $ ikarus --r6rs-script test.ss
> Unhandled exception:
>   Condition components:
>     1. &who: let
>     2. &message: "not an identifier"
>     3. &syntax:
>         form: (let ((17 b)) (list a b))
>         subform: 17
>     4. &trace: #<syntax (let ((17 b)) (list a b))>
>     5. &trace: #<syntax (foo 17 b (list a b))>
>     6. &trace: #<syntax (bar b 17 (list a b)) [byte 200 of test.ss]>

Why I don't get the traceback? My output stops at point 3. Are you
referring to a development version of Ikarus, or there is a debug
flag I should set somewhere to see the traceback? I am using
Ikarus 0.0.3.

      Michele Simionato
From: Abdulaziz Ghuloum
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fp38er$otg$1@aioe.org>
·················@gmail.com wrote:

> Why I don't get the traceback? My output stops at point 3. Are you
> referring to a development version of Ikarus, or there is a debug
> flag I should set somewhere to see the traceback? I am using
> Ikarus 0.0.3.

I just added that yesterday :-)  So, you can get it from the repo:

$ bzr checkout --lightweight http://www.cs.indiana.edu/~aghuloum/ikarus.dev
From: Kaz Kylheku
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <e57a45bc-78db-4f68-84df-1ca3ece2a8ad@s12g2000prg.googlegroups.com>
On Feb 14, 4:30 pm, Abdulaziz Ghuloum <········@cee.ess.indiana.edu>
wrote:
> $ ikarus --r6rs-script test.ss
> Unhandled exception:
>   Condition components:
>     1. &who: let
>     2. &message: "not an identifier"
>     3. &syntax:
>         form: (let ((17 b)) (list a b))
>         subform: 17
>     4. &trace: #<syntax (let ((17 b)) (list a b))>
>     5. &trace: #<syntax (foo 17 b (list a b))>
>     6. &trace: #<syntax (bar b 17 (list a b)) [byte 200 of test.ss]>
>
> As you can see, it shows the original file name and position in
> terms of the user's original source code.  

S-expressions read from a file (and all their constituent
expressions), can be associated this information in a global hash
table. Given some erroneous form, the macro can see if there is
associated information with that form.

In principle, the origin of every literal object (or at least that of
every boxed one) that was read from some source file can be
pinpointed.

> Some may think that this advantage does not outweigh dropping
> the raw s-expression form.

It doesn't seem to /technically/ require such dropping.

> But others value things differently.

E.g. eating the cake and having it too.
From: Abdulaziz Ghuloum
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <fp39b4$rnu$1@aioe.org>
Kaz Kylheku wrote:

>> Some may think that this advantage does not outweigh dropping
>> the raw s-expression form.
> 
> It doesn't seem to /technically/ require such dropping.

Neither did I say it was, nor am I going to attempt to
prove otherwise.  Actually, there may already exist some
system that somehow manages to pull it off, but to my
limited knowledge, I have not seen it done.  Moreover,
adding the trace to my expander took no more than 45
minutes of doing minor edits to one file.  Additionally,
the trace information (which is associated with the syntax
objects themselves) is not interned anywhere, and works
across files and will just work even with separately
compiled libraries.

All I show here is the advantage that *I* got from having
special syntax objects over having to use s-expressions.
Mileages vary.

Aziz,,,
From: Jens Axel Soegaard
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <47b822a9$0$15882$edfadb0f@dtext01.news.tele.dk>
Kaz Kylheku wrote:
> On Feb 14, 4:30 pm, Abdulaziz Ghuloum <········@cee.ess.indiana.edu>

>> As you can see, it shows the original file name and position in
>> terms of the user's original source code.  
> 
> S-expressions read from a file (and all their constituent
> expressions), can be associated this information in a global hash
> table. Given some erroneous form, the macro can see if there is
> associated information with that form.

How does a hash table system handle S-expressions generated
by macros? Does it store every return value generated by
macro transformers along with the location of the macro
definition?

-- 
Jens Axel S�gaard
From: Pascal Costanza
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <61qo85F1vfulnU1@mid.individual.net>
Kaz Kylheku wrote:
> On Feb 14, 4:30 pm, Abdulaziz Ghuloum <········@cee.ess.indiana.edu>
> wrote:
>> $ ikarus --r6rs-script test.ss
>> Unhandled exception:
>>   Condition components:
>>     1. &who: let
>>     2. &message: "not an identifier"
>>     3. &syntax:
>>         form: (let ((17 b)) (list a b))
>>         subform: 17
>>     4. &trace: #<syntax (let ((17 b)) (list a b))>
>>     5. &trace: #<syntax (foo 17 b (list a b))>
>>     6. &trace: #<syntax (bar b 17 (list a b)) [byte 200 of test.ss]>
>>
>> As you can see, it shows the original file name and position in
>> terms of the user's original source code.  
> 
> S-expressions read from a file (and all their constituent
> expressions), can be associated this information in a global hash
> table. Given some erroneous form, the macro can see if there is
> associated information with that form.
> 
> In principle, the origin of every literal object (or at least that of
> every boxed one) that was read from some source file can be
> pinpointed.

No, not in general. S-expressions can share subforms, and then such 
information is not unambiguous anymore.


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: gavino
Subject: Re: What's up with Scheme macros?
Date: 
Message-ID: <a39ec448-eaae-4715-9cd4-2e5560fa3670@s8g2000prg.googlegroups.com>
On Feb 12, 1:46 am, Ken Tilton <···········@optonline.net> wrote:
> While trying to explain my irrational prejudice against Scheme macros I
> got curious as to why I hated them, so I googled up this:
>
>    http://www.xs4all.nl/~hipster/lib/scheme/gauche/define-syntax-primer.txt
>
> Boys and girls, that is almost eleven thousand words long!!!!!
>
> I see the problem, they have this whole pattern-matching syntax-rules
> language moving from source input to output. I have done (and am
> supposed to be doing) enough Prolog to realize Scheme macro writers must
> be way smarter than me. But... why? No, not why are they smarter. Why do
> they have to be smarter? What was wrong with treating the source as an
> ordinary tree of data and just whinging it about with Scheme itself to
> produce the output? Please restrict yourself to one or more of these
> answers:
>
> 1. The hygiene made us do it.
>
> 2. We actually thought it would be way cool and super powerful.
>
> 3. We were embarrassd by the small size of the standard and decided to
> make it up in the macro language
>
> 4. Other _____________________
>
> Jes curious,
>
> kenny
>
> --http://smuglispweeny.blogspot.com/http://www.theoryyalgebra.com/
>
> "In the morning, hear the Way;
>   in the evening, die content!"
>                      -- Confucius

comedy galore