[plt-scheme] Macro is misbehaving...

From: Ryan Culpepper (ryan_sml at yahoo.com)
Date: Mon Jun 12 13:53:18 EDT 2006

--- "Paulo J. Matos" <pocmatos at gmail.com> wrote:

> On 12/06/06, Ryan Culpepper <ryan_sml at yahoo.com> wrote:
> > --- "Paulo J. Matos" <pocmatos at gmail.com> wrote:
> >
> > > Hi all,
> > >
> > > I'm having a macro that's giving me the creeps. I've
> oversimplified
> > > it, but the error is still there so don't worry if it really
> > > doesn't
> > > make sense, what matters is why this is happening:
> > > foo.scm
> > > (module foo mzscheme
> > >
> > >   (require (prefix slide: (lib "slide.ss" "slideshow"))
> > >            (lib "class.ss"))
> > >
> > >   (define obj%
> > >     (class object%
> > >       (define/public (get-pict s)
> > >         (slide:inset 10 10))
> > >       (super-new)))
> > >   (define obj (make-object obj%))
> > >
> > >   (define-syntax slide/foo
> > >     (syntax-rules ()
> > >       ((_ obj s ...)
> > >        (slide:slide
> > >         (if (symbol? s)
> > >             s
> > >             (send* obj s))
> > >         ...))))
> > >
> > >   (provide slide/foo)
> > >   )
> > >
> > > bar.scm
> > > (module bar (lib "slideshow.ss" "slideshow")
> > >
> > >   (require "foo.scm")
> > >
> > >   (slide/foo
> > >    (t "Hello")
> > >    'next
> > >    (t "Bye"))
> > > )
> > >
> > > I get:
> > > expand: unbound variable in module in: next
> >
> > (slide/foo (t "Hello") (quote next) (t "Bye"))
> > =>
> > (slide:slide
> >   (if (symbol? (quote next))
> >       (quote next)
> >       (send* (t "Hello")
> >         (quote next))))
> >
> > You are producing a send* expression that tries to call the
> > "quote" method with the single argument "next". That's why
> >  you're getting the error about "next" being unbound.
> >
> 
> I'm sorry but I still cannot understant what the problem is. (quote
> next) doesn't need to evaluate next. (symbol? (quote next)) => #t,
> so it should return the symbol.

The expression your macro produces contains this code:

  (send* (t "Hello") (quote next))

Of course, that branch of the if expression will never be executed.
But it is still expanded and compiled, and that means that if it
contains an unbound variable, the expander/compiler will signal an
error (which it does).

Why does that expression have an unbound variable? Well, even though
"(quote next)" looks like an expression in there, the send* form
actually interprets it as a message name ("quote") followed by a list
of arguments (just one---the variable "next").

> > You are also duplicating the evaluation of "s"---you shouldn't do
> > that either.
> 
> I know, that's the part of the oversimplification to show here.

Okay.

> > > wierder is that if I change send* to send I get:
> > > send: method name is not an identifier in: (quote next)
> >
> > Yes, because in that case you have
> >
> >   (send (t "Hello") (quote next))
> >
> 
> This one was a stupid try because it would not work.
> The fact is that the macro receives a list with a method and its
> arguments, so that's why I call send* instead of send. I receive
> (method args) so (send* obj (method args)) would work.
> 
> > so it's trying to interpret "(quote next)" as the name of the
> > method to call.
> >
> 
> Yes, I understand that, thanks.
> 
> > > Problem is, I need to send an the argument of slide/foo to an
> > > object unless this argument is 'next, 'alt, generally speaking:
> > > a symbol. I'm not being able to do this. Any ideas?
> >
> > Do you mean to always call the "get-pict" method if it isn't a
> > symbol? That's missing from your macro.
> >
> > My hunch is you want the else branch of the if expression to be
> >
> >   (send obj get-pict s)
> >
> 
> No, not really, again a problem with oversimplification. If I call,
> for example, (slide/foo (get-pict 10)) I would like it to call
> the method get-pict with arg 10 on the object.
> If I call (slide/foo 'next) it should return next.

Okay, I'm starting to see the problem.

You want to distinguish between two cases:
1) If "s" *evaluates to*  a symbol, then return the symbol
2) If "s" *has the syntactic form* (method arg ...), then call the
method

You are mixing static and dynamic criteria. Instead, why don't you
rewrite the first case as:
1) If "s" has the syntactic form of just the identifier "next"

Then you can write the macro like this:

(define-syntax slide/foo
  (syntax-rules (next)
    [(slide/foo obj next)
     'next]
    [(slide/foo obj (method arg ...))
     (send obj method arg ...)]))

(I'll let you generalize it to multiple things after the "obj".)

> Still, can't understand your explanation on why this doesn't work.
> next should never be evaluated. Afterall (quote next) is exactly
> not to evaluate next.

Only if "(quote next)" is used as an expression. In the code your
macro produced, it wasn't.

Ryan

> > > _________________________________________________
> > >   For list-related administrative tasks:
> > >   http://list.cs.brown.edu/mailman/listinfo/plt-scheme



Posted on the users mailing list.