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.