[plt-scheme] Not so hygienic macros?

From: Eli Barzilay (eli at barzilay.org)
Date: Tue Dec 29 03:03:31 EST 2009

On Dec 29, Robby Findler wrote:
> On Mon, Dec 28, 2009 at 9:02 PM, michael rice <nowgate at yahoo.com> wrote:
> > OK, here's some code (at bottom) to work with. Use of MATCH seems
> > to cause a lot of problems. Code is actually Scheme translation of
> > some Logo code from an old TLC Logo book (for the Mattel Aquarius
> > no less) authored by John R. Allen.
> I think you're running into what Matthew calls "hopeless top-level
> problems". Eli can probably say more about what is going on with the
> Swindle language that leads to these precise results.

I missed the problem since there wasn't a clear file...  The short
version is that Robby's right, and you should use the "Module"
language.  If you want to know what exactly went wrong, then...

The problem is indeed the top-level problem, and it is not really
related to Swindle (but see below).  A number of languages in DrScheme
work by evaluating the code in a kind of a REPL, and this gets messy
when macros are involved.  Here's a small example which fails in many
of these langauges:

  (define cond (lambda (x) (if (= x 0) x (cond (- x 1)))))
  (cond 10)

Try this in Pretty Big, or R5RS, or EoPL, and the answer is 1.  What
happens here is that `cond' is the usual macro when evaluation starts.
Then, the expression is evaluated, and then the binding is created.
So when the expression is evaluated, `cond' is still the usual macro,
and finally it is bound to a function that given any non-zero number
will return one because it uses the *macro* instead of doing a
recursive call.

But in Swindle this does *not* happen -- in a questionable attempt
(that was done ages ago) to make things saner, swindle has a `define'
form that, when used in a top-level context, translates the code to:

  (define cond (void))
  (set! cond (lambda (x) (if (= x 0) x (cond (- x 1)))))

However, you've added (require eopl/eopl) -- and this:

  (require eopl/eopl)
  (define cond (lambda (x) (if (= x 0) x (cond (- x 1)))))
  (cond 10)

fails in the Swindle too -- because that `require' means that the eopl
`define' is used, and that one doesn't do the same trick.

In your case, you get the same problem with `match', which is also
provided as a macro by these languages, and the "recursive call" is
just a use of the macro that happens to follow a syntax that the
`match' accepts.  (You can change this call to (match (cdr pat1) 1)
and see that you get a syntax error that comes from the match macro.)

In the Module language, each file is a complete module.  In this case
the code is evaluated in such a way that properly finds all
definitions, and this means that it knows to never use the `match'
macro, and instead compile it as a function call -- IOW, it does what
you thought it should do.

          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                    http://barzilay.org/                   Maze is Life!

Posted on the users mailing list.