schemeracketguilechicken-schemegambit

Nested ellipsis macro doesn't work in Guile and Racket


I'm trying to create a simple nested macro. It works in my Scheme implementation, but fails to run in Guile and Racket.

(define-syntax foo
  (syntax-rules (:c)
    ((_ x ...)
     (let-syntax ((bar (syntax-rules ::: (:c)
                         ((_ x)
                          (print x))
                         ((_ a b :::)
                          (begin
                            (display a)
                            (display " ")
                            (bar b :::))))))
       (bar x ...)))))

syntax: missing ellipsis

missing ellipsis with pattern variable in template

I've also tried to run in Gambit, but that one just throws:

Unbound variable: define-syntax

I guess you need to use a library to use a basic scheme.

In Checken Scheme, after updating ellipsis:

(define-syntax foo
  (syntax-rules (:c)
    ((_ x ...)
     (let-syntax ((bar (syntax-rules <:::> (:c)
                         ((_ x)
                          (print x))
                         ((_ a b <:::>)
                          (begin
                            (display a)
                            (display " ")
                            (bar b <:::>))))))
       (bar x ...)))))

throws:

template dimension error (too few ellipses?): x

What's wrong with this macro? Why does it throw an error?

EDIT:

It seems that this pattern is not valid:

(_ x ...)

but this is

(_ x y ...)

Is this specified somewhere? Why the first syntax is not valid?

Just to be complete, this code compiles, but why the first doesn't?

(define-syntax foo
  (syntax-rules ()
    ((_ x y ...)
     (let-syntax ((bar (syntax-rules <:::> ()
                         ((_ x)
                          (print x))
                         ((_ a b <:::>)
                          (begin
                            (display a)
                            (display " ")
                            (bar b <:::>))))))
       (bar x y ...)))))

But it doesn't work when tried to use foo macro. It throws:

unbound variable: bar

even when using letrec-syntax.


Solution

  • The problem is that ellipsis are following x in your outer macro. This means the template that is produced should also have ellipsis following x, which it doesn't. If you rename the inner macro's x to y it should work as you expect.

    In other words, what you're doing here is equivalent to:

    (define-syntax foo
      (syntax-rules ()
        ((_ x ...)
         (display x))))
    

    Which wouldn't be allowed either. If you have x with ellipsis in the pattern, you must also consume those ellipsis when consuming x in the template that follows it.

    The reason it works if you make it (x y ...) is that y (and its ellipsis rest) is not consumed at all by the template.