[plt-scheme] define-syntax by itself

From: Jens Axel Søgaard (jensaxel at soegaard.net)
Date: Sat Sep 9 18:57:55 EDT 2006

Blake McBride skrev:
> At 04:49 PM 9/9/2006, Jens Axel Søgaard wrote:
>> Blake McBride skrev:
>>
>>> 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
>>> So if stx represents the "foo" token, how do you get to the 6?
>>
>> You missed that the transformer is called twice.
>>
>>  To expand (foo 6) the transformer is called with the syntax-object
>>  #'(foo 6).
>>  The (car (syntax-object->datum stx)) extract the symbol foo,
>>  and the (datum->syntax-object stx ...) converts it to an identifier
>>  that are returned as the result.
>>
>>  Now the result is expanded. Now the transformer is called with
>>  the single identifier #'foo. The (syntax-object->datum stx)
>>  converts it to the symbol 'foo. And now (car 'foo) gives
>>  the error you see.
>>
>> To get the 6 take the cadr instead of the car.
>>
>> (define-syntax foo
>>   (lambda (stx)
>>     (datum->syntax-object stx
>>                           (cadr (syntax-object->datum stx)))))
> 
> I'm confused.  In my example car of (foo 6) returns foo.
> Then its called again and I get the error when attempting
> a car on foo.
> 
> You use cadr.  Let's follow this through with the same logic.
> The first time you are doing a cadr on (foo 6) yielding 6.
> But, when it goes through again it should be attempting a
> cadr on the 6.  That shouldn't work either.

Expanding a 6 doesn't call the transformer of foo.
Expanding a 6 simply becomes a 6.

> I think I am confused about the steps happening.  In lisp
> macros it too goes through two passes.  The first time
> the macro code is executed to create an s-expression.
> Then the s-expression is evaluated.  

Yes. And if the s-expression is a macro call, then
the s-expression is expanded again. So define-syntax
and "lisp" behaves the same way.

> Something different is happening with define-syntax.

No.

> First of all I'm dealing with
> a syntax object instead of an s-expression in the first pass
> at least.

Yes.

> If I do (syntax-object->datum stx) do I get the s-expression
> just like the lisp macro stuff?

 From the documentation:

   (syntax-object->datum stx) returns an S-expression by stripping the
   syntactic information from stx. Graph structure is preserved by the
   conversion.

> If so, I should be able to manipulate it any way I like and then
> run datum->syntax-object on it in the end to turn it back into
> a syntax object to be evaluated.

More or less. You have to be careful not to delete any
contextual information of identifiers.

The difference between a syntax-object representing a symbol
(also known as an identifier) and a symbol is that the identifier
carries lexical information. If you simply convert it to
a symbol and then back again with (syntax-object->datum stx 'bar),
then the resulting identifier will get the lexical information
from stx. This may or may not be what you want.

Take a look at

   <http://schemecookbook.org/view/Cookbook/GettingStartedMacros>

and in particular

   "Writing Hygenic Macros in Scheme with Syntax-Case"

by Dybvig.

-- 
Jens Axel Søgaard




Posted on the users mailing list.