[plt-scheme] Re: define-syntax by itself

From: Eli Barzilay (eli at barzilay.org)
Date: Sat Sep 9 17:46:56 EDT 2006

On Sep  9, Blake McBride wrote:
> At 02:09 PM 9/9/2006, Eli Barzilay wrote:
> >On Sep  9, Blake McBride wrote:
> > >
> > > I probably mean something like procedural macros that allow you to
> > > specify exactly what you want without trying to do it in some higher
> > > level 4th generational descriptive pattern language.  I believe
> > > there is an SRFI about this.
> >
> >Well then, `define-syntax' does just that.  When you write:
> >
> >   (define-syntax foo
> >     (lambda (stx)
> >       ...))
> >
> >you bind `foo' -- as a syntax -- to a syntax->syntax transformer
> >procedure.  How you implement the procedure is up to you --
> >`syntax-rules' can construct simple transformers very easily, and
> >`syntax-case' gives you only the pattern matching part in an easy
> >way.  But nothing prevents you to write your own body in the above
> >definition, and you can use the basic syntax manipulation tools
> >(syntax-e, syntax-object->datum and datum->syntax-object).
> This is very interesting to me.  If I could deal with syntax objects
> the way I want and go back and forth between syntax objects and
> scheme objects I would be able to do anything I wanted.  Once I get
> a good understanding of all this I could better understand what the
> heck is going on with syntax-case.

One thing you'll get is a headache...  There are lots of details that
you avoid by using things like `syntax-case'.

> I'd like to play with this.  I did try for a few minutes and
> couldn't get anywhere.  For starters, on entry stx, I presume, is a
> syntax object representing my call.  I presume the lambda must also
> return a syntax object.  Since stx is already a syntax object I
> tried:
> (define-syntax foo
>    (lambda (stx)
>         stx))
> (foo 6)
> and the system hangs.

Right -- you made that expression expand to `(foo 6)', so expansion
gets stuck in an infinite loop.  (But not really, see below.)

> If I try:
> (define-syntax foo
>    (lambda (stx)
>      (datum->syntax-object stx (car (syntax-object->datum stx)))))
> (foo 6)
> I get:  car: expects argument of type <pair>; given foo

What happens here is that syntax transformers can be used as
expressions in MzScheme -- so in the above, it first uses `foo'
itself -- which is passed on to your transformer procedure.
`syntax-rules' does not allow such a case, which is why you get a
syntax error when you try to use a macro as an expression.  (And you
can now see that the above infinite loop is a little different.)

> So if stx represents the "foo" token, how do you get to the 6?

  (define-syntax (foo stx)
    (let ([l (syntax->list stx)]) ; l will be a list or #f
      (unless (and l (< 1 (length l)))
        (error "boom"))
      (cadr l)))

or maybe expand (foo x) => (list 'x '-> x):

  (define-syntax (foo stx)
    (let ([l (syntax->list stx)])
      (unless (and l (< 1 (length l)))
        (error "boom"))
      (datum->syntax-object stx
        (list #'list (list #'quote (cadr l)) (list #'quote '->) (cadr l)))))

> [...]
> I really like your suggestion.  I just can't figure our how to get
> it to work at all.  (I'd prefer to avoid syntax-e since it doesn't
> seem to be standard.)

The above uses `syntax->list' which is also non-standard.  But none of
this is standard anyway -- if you want only standard stuff, then you
should stick to `syntax-rules' only...  (Which means that you're out
of luck because there is no standard low-level macro facility in
Scheme (yet).)

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

Posted on the users mailing list.