On 03/27/2018 10:01 PM, Justin Pombrio wrote:
I'm surprised by the behavior of using a pattern variable under one set of ellipses in the pattern, and under two sets of ellipses in the template:

|
#lang racket

(require(for-syntax syntax/parse))

(define-syntax (test stx)
(syntax-parse stx
[(_ (x y ...)...)#''(top (list (x y) ...) ...)]))

(test (a 123)
(b 456)
(c 789))
|

I would expect this to produce:

|
'(top (list (a 1) (a 2) (a 3))
       (list (b 4) (b 5) (b 6))
       (list (c 7) (c 8) (c 9)))
|

But instead, it produces:

|
'(top (list (a 1) (b 2) (c 3))
       (list (a 4) (b 5) (c 6))
       (list (a 7) (b 8) (c 9)))
|

I'm surprised by this for two reasons:
- What I thought was the obvious implementation for matching/substituting with ellipses produces the top answer.
- It breaks some properties that I would expect ellipses to have, such as:

|
(define-syntax-rule (test (P ...))(list Q ...))
(test (T1 T2))
===
(define-syntax-rule (test P P*)(list Q Q*))
(test T1 T2)

;forall patterns P andtemplates Q andterms T1 andT2,whereP*andQ*are a renamed version of P andQ.
|

This has extra parens or is missing dots or something. As it is, the top test takes 1 argument and the bottom test takes two.

Is this the expected behavior? And is there a good reason for it?

A variable must participate in as many of the implicit maps in the template as its ellipsis depth from the *pattern* (call that depth D). If it occurs at a greater depth in the template, there are three obvious choices: participate in the outermost D maps, participate in the innermost D maps, or reject the template. At some point, someone decided to go with the innermost maps.

It's actually more complicated that that, because a variable can occur at multiple depths in the same template. Consider this example:

  > (with-syntax ([(x ...) #'(1 2 3)])
      #'((x x ...) ...))
  #<syntax:2:4 ((1 1 2 3) (2 1 2 3) (3 1 2 3))>

Instead of the property you were expecting, you get the following property: If T is a "fully-saturated" template (all variables occur wrt T at a depth >= their binding depths), then T always produces the same output, even when you put it in a larger template with more ellipses.

I think it might have been helpful back in the R5RS days, when "portable" macros were limited to syntax-rules, and this decision made a very limited system slightly more flexible. (To clarify, I'm not sure that R5RS specified this behavior, but I think it was a common extension to syntax-rules, whereas with-syntax was not.)

Nowadays, I would rather rewrite the macro to use with-syntax than rely on this "feature". I've implemented it twice, and I still have to stop and think through it.

Ryan

--
You received this message because you are subscribed to the Google Groups "Racket 
Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to