[plt-scheme] macros: incompatible ellipsis match counts

From: Jon Rafkind (workmin at ccs.neu.edu)
Date: Tue Feb 13 22:41:25 EST 2007


Matthew Flatt wrote:
> At Mon, 12 Feb 2007 20:16:04 -0500, Jon Rafkind wrote:
>   
>> Matthew Flatt wrote:
>>     
>>> The rules for ellipses always take a while for me to page back in...
>>>
>>> At Mon, 12 Feb 2007 14:50:58 -0800 (PST), Ryan Culpepper wrote:
>>>   
>>>       
>>>>> (define-syntax foo3
>>>>>   (syntax-rules ()
>>>>>     ((_ ((z ...) f ...) ...)
>>>>>      (begin
>>>>>        (begin
>>>>>          (begin z f ...) ...)
>>>>>        ...)
>>>>>        )))
>>>>>       
>>>>>           
>>>> This 'syntax-rules' expression is wrong. The 'z' pattern variable has
>>>> an ellipsis-depth of 2, and the 'f' pattern variable also has an
>>>> ellipsis-depth of 2. In the template, though, you're using 'f' at a
>>>> depth of 3. Usually that kind of error is caught at compile time.
>>>>     
>>>>         
>>> It's ok to have extra ellipses after a pattern variable in a template.
>>> The rule is that the innermost ellipses are treated in the usual way,
>>> and then the overall result is repeated as many times as necessary for
>>> remaining ellipses (where the repeat count for each remaining ellipses
>>> is determined by some other variable).
>>>
>>> Meanwhile, the count for each ellipses must be determined by at least
>>> one pattern variable. Incompatible-count errors are possible if the
>>> count is determined by more than one variable.
>>>
>>> In this case:
>>>
>>>         (begin
>>>           (begin z f ...) ...)
>>>         ...)
>>>
>>> The count for the first `...' is determined by `f', the count for the
>>> second `...' is determined by both `z' and `(f ...)', and the count for
>>> the last is determined by `(z ...)'.
>>>
>>>   
>>>       
>> I think you lose me right about here. Why does the last ellipses depend 
>> on `(z ...)' and not `((z ...) f ...)' ?
>>     
>
> Because the first two ellipses cover `f'. Whatever those two generate
> for `f' will be repeated as many times as determined by `z'.
>
>   
>> I thought ... matched the 
>> previous s-expression in its entirety.
>>     
>
> Yes, but the last `...' is the 3rd one for `f', and so it just causes
> repeats of whatever `(f ...) ...' generates.
>
>   
>> Also it feels to me like the second set of ellipses shouldn't depend on 
>> both z and f.
>>     
>
> But you just pointed out that `...' applies to everything before, which
> in this case is `(z f ...)'. Neither `z' nor `f' is maxed out in
> ellipses at `(z f ...)', so `...' attaches to both.
>
>   
>> Since f is already repeated in the begin the outer ... 
>> should just repeat the begin for each z.
>>     
>
> It could make sense to say that the first `...' applies to just `f',
> the second applies to just `z' (with `(f ...)' results repeated), and
> the last applies to both `z' and `f' --- and maybe that's what you want
> in this case. Indeed, I suppose a more general template system would
> let you annotate each `...' with the pattern variables on which it's
> supposed to apply. Without those annotations, though, I don't see how
> the template system would arrive at the mapping that you want.
>
>   
Is it more concise to say that the number of z's has to match the number 
of f ...'s for the same reason the number of z's has to match the number 
of f's in the following macro
(define-syntax foo
  ((_ (z ...) (f ...))
   (begin (begin z f) ...))))

I played with the macro a little more and added yet another set of ellipses

(define-syntax foo3

  (syntax-rules ()
    ((_ (((z ...) f ...) ...) ...)
     (begin
       (begin
         (begin
           (begin z f ...) ...)
         ...)
       ...)
     )))

(foo3 (((1 2 3) 4 5 6) ((1 2 3) 1) ((1 2 3) 1 2))
      (((1 2 3) 4 5 6) ((1 2 3) 1) ((1 2 3) 1 2))
      (((1 2 3) 4 5 6) ((1 2 3) 1) ((1 2 3) 1 2)))

(foo3 (((1 2) 4 5 6) ((1 2) 1))
      (((1 2) 4 5 6) ((1 2) 1)))

You can see that the number of z's determine the number of rows and 
columns, because the number of z's has to equal the number of f ... 
expressions and f ... .... expressions, or maybe the number of z ... 
expressions has to equal the number of f ... ... expressions, I'm not 
exactly sure but the z's definately determine the rest anyway.
> The original template implementation in MzScheme had outer `...' taking
> precedence over inner `...'. It worked, but it was less useful than
> having inner `...' take precedence. So there is certainly some choice
> in the automatic mapping, but some choices seem to be more useful than
> others.
>
> In any case, at some point maybe it's better to use `map'. :)
>
>   
Probably. This whole example is somewhat artificial.. I was explaning 
macros to a friend and this stumped me.


Posted on the users mailing list.