[plt-scheme] macro writing

From: Carl Eastlund (cce at ccs.neu.edu)
Date: Tue Jun 20 03:49:49 EDT 2006

On 6/20/06, Ivanyi Peter <pivanyi at freemail.hu> wrote:
> I would like to do something like this. How can I solve the
> problem
> to have a second ellipses in the list after "locals"? Can
> somebody help
> me with this or point to the right direction?
> (Macro writing is not my strength.)

Let me see if I can help.  Obviously you can't do it the way you tried
- syntax-rules doesn't allow anything after the ellipsis (the "...")
in a pattern.  So you're going to have to do something else to
separate your arguments from your local definitions.

> (define-syntax call
>   (syntax-rules ( locals )
>     ((_ n1 (v1 v2 ... locals v3 v4 ...) e1 e2 ...)
>      (define (n1 v1 v2 ...)
>        (let*
>          ((v3 #f) (v4 #f) ...)
>          e1 e2 ...
>        )))))
> (call aa (a b locals c)
>   (set! c 3)
>   (+ a b c)
> )

I assume you want the above to expand to:

(define (aa a b)
  (let* ((c #f))
    (set! c 3)
    (+ a b c)))

Off the top of my head, I can think of three options for you.

Separate the definitions manually.  Match on the following pattern initially:

(syntax-rules ()
  ((_ n1 (any-names ...) e1 e2 ...)
   <code here>))

And in <code here>, write code to manually search through (syntax
(any-names ...)) for the keyword "locals".  Then you can construct
separate lists or syntax objects for arguments and local definitions.

Change the pattern.  Match on this pattern:

(syntax-rules ()
  ((_ n1 (v1 v2 ...) (v3 v4 ...) e1 e2 ...)
   <code here>))

So your example becomes:

(call aa (a b) (c)
  (set! c 3)
  (+ a b c))

Write separate macros, one for defining functions with arguments and
one for defining local names.  Your example might look like:

(call aa (a b)
  (locals (c)
    (set! c 3)
    (+ a b c)))

Of course at this point, you might as well use "define" instead of
"call"; the only new syntax is "locals" which defines a set of names
and initializes them to #f.

As a separate note, you might also consider initializing locals to the
undefined value using letrec, instead of #f.  It might give clearer
error messages (seeing #<undefined> instead of #f tells the user what
went wrong).  In the third suggestion, that would look like:

(define-syntax locals
  (syntax-rules ()
    ((_ (name ...) e1 e2 ...)
     (letrec ((name name) ...)
      e1 e2 ...))))

I hope this was helpful.  Let me know if you have questions about any
of my slew of suggestions.

Carl Eastlund
"Cynical, but technically correct."

Posted on the users mailing list.