Macroexpand

Jan 13, 2010 at 2:47 AM

Is there any way to macroexpand a macro?

Thanks!

 

Coordinator
Jan 13, 2010 at 5:30 AM

Hi

There is a way, but it is very hard to use. I have maybe used it once or twice.

I suggest using PLT DrScheme using the macro stepper.

Another way to help debug expansion while developing a macro is to use the tracing facilities.

Example:

> (trace-define-syntax foo (identifier-syntax 'poo))
> foo
| -> foo
foo
| <- foo
'poo
poo
>

There is also syntax-trace, which is like syntax-case but with some expand time tracing.

Cheers

leppie

Jan 13, 2010 at 2:07 PM

Thx. Will do.

Jan 25, 2010 at 4:42 AM

Could you expand on what you said about macroexpanding being difficult? Maybe the technique? It doesn't seem that it would be that hard.

Coordinator
Jan 25, 2010 at 5:24 AM

Well you can try it, but it is difficult  :) 

Here is something to get you going:

> (expand->core '(let ((a 1)) a) (interaction-environment))
((case-lambda ((g$a$3$1HFvW6) g$a$3$1HFvW6)) '1)

1. The environment parameter is tricky, interaction-environment is ok for simple stuff, like above.

2. The output is full of gensyms, and all constant data is quoted.

3. Some variables may refer to syntax (which could obfuscate it a bit more).

Cheers

leppie

Jan 25, 2010 at 6:04 AM
Edited Jan 25, 2010 at 6:05 AM

Ah. I can see the light:) Well, atleast the variable and function names are in the gensyms. Err... Do you know why (expand->core '(clr-cond () (() (display "go"))) (interaction-environment)) returns an error?

Unhandled exception during evaluation:
&assertion
&who: "car"
&message: "not a pair"
&irritants: (())

 

 

Jan 25, 2010 at 7:09 AM
Edited Jan 25, 2010 at 7:10 AM

This doesn't appear to work when attempting to expand a redefined let like this:

(let-syntax ((add (syntax-rules () ((_ a b) (* a b))))
         (let (syntax-rules () ((_ else ...) (letr else ...)))))
 
  (expand->core '(let ((a 2)) (add 2 a)) (interaction-environment)))

expands to

((case-lambda ((g$a$2554$1Hr@99) (g$+$16380$xVrU3 '2 g$a$2554$1Hr@99))) '2)

The reason I would like this is because im trying to figure a way how to make this slightly more human readable, basically not expanding a let. If i use a let in the let-syntax, it appropriately throws an error that

letr doesn't exist.

Any ideas why I can redefine the add macro (I previously had it adding) while i can't redefine the let macro?

 

Coordinator
Jan 25, 2010 at 7:48 AM

Did you just post this: https://answers.launchpad.net/r6rs-libraries/+question/98600

If so, you will probably find a better answer there.

The likely cause is the environment. You will need to have all the required libraries loading in the interaction-environment for this to work.

To 'ungensym' a gensym:

> (ungensym 'g$a$2554$1Hr@99)
a

Basically, between the first and second $ is the name token, the second token is just an incremented index, while the third is a timestamp. This all is needed to create truly unique gensyms that works over multiple sessions.

Some may not work, as they are just temporaries.

Jan 25, 2010 at 6:17 PM

This is good to know! Yes, that was me. I think adding a macroexpand-1 and preventing certain common forms from expanding (like let) would dramatically increase anyones debugging efficiency.

Coordinator
Jan 25, 2010 at 6:34 PM

I dont you can have a lisp like macroexpand-1 as per your example.

The way I understand how macros expand are from outside in, so in your case LET will always be expanded first before its arguments.

Example:

> (define-syntax foo (syntax-rules () [(_) poo]))
> (let (((foo) 1)) #t)
Unhandled exception during evaluation:
&who: let
&message: "not an identifier"
&syntax:
  form: (let (((foo) 1)) #t)
  subform: (foo)
&trace: #

So FOO will never be expanded first.

I would still suggest using the tracing facilities. IE

trace-define-syntax
trace-letrec-syntax
trace-let-syntax
trace-define
trace-lambda
Note: you will loose tail calls to traced procedures, but not that that matters when you debugging  :)

Jan 25, 2010 at 6:47 PM

Hmm... true. I sort of messed up on that example, lisp also expands outward to inward. I guess what i want to do is expand the outermost macro once  instead of expanding everything.

So i dont quite get this tracing of macros.

 

(define-syntax add (syntax-rules () ((_ a b) (+ a b))))
(trace-define-syntax pow (identifier-syntax 'add))
(pow 2 3)
Unhandled exception during evaluation:
&who: generator
&message: "expecting a procedure"
&syntax:
  form: 'add
  subform: ('add '2 '3)

 

Whats it supposed to do?

 

Coordinator
Jan 25, 2010 at 6:54 PM

Drop the quote  :)

(trace-define-syntax pow (identifier-syntax add))