[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Choose-Your-Own-Ellipsis



I think the better approach to the nested ellipsis problem is to have
syntax-rules take as an (optional) argument the identifier that you
wish to use to indicate sequences.  E.g.:

  (define-syntax generate-temporaries
    (syntax-rules ()
      ((_ ?origs ?k)
       (letrec-syntax
	   ((aux (syntax-rules ::: () ;; use ":::" as ellipsis
		   ((_ ?temps () ?k*)
		    (apply-syntax-cont ?k* ?temps))
		   ((_ (?temp :::) (?x ?more :::) ?k*)
		    (aux (?temp ::: new-temp)
			 (?more :::)
			 ?k*)))))
	 (aux () ?origs ?k)))))

Alternatively:

  (define-syntax generate-temporaries
    (syntax-rules this-ellipsis-id-is-not-used ()
      ((_ ?origs ?k)
       (letrec-syntax
	   ((aux (syntax-rules () ;; use default "..." ellipsis
		   ((_ ?temps () ?k*)
		    (apply-syntax-cont ?k* ?temps))
		   ((_ (?temp ...) (?x ?more ...) ?k*)
		    (aux (?temp ... new-temp)
			 (?more ...)
			 ?k*)))))
	 (aux () ?origs ?k)))))

This approach doesn't have any problem with matching an ellipsis as
part of a pattern, or with expanding into things like (x . ...), and
it doesn't lead to goofy constructions like ((... ...) (... ...)).  If
you want to nest three levels and be able to indicate a sequence at
any level, just choose three different ellipses.

Furthermore, there's no need to daintily pass ?k around in the example
above.  You can just do:

  (define-syntax generate-temporaries
    (syntax-rules ()
      ((_ ?origs ?k)
       (letrec-syntax
	   ((aux (syntax-rules ::: () ;; use ":::" as ellipsis
		   ((_ ?temps ())
		    (apply-syntax-cont ?k ?temps))
		   ((_ (?temp :::) (?x ?more :::))
		    (aux (?temp ::: new-temp)
			 (?more :::))))))
	 (aux () ?origs)))))

and rely on hygienic renaming to prevent any uses of ::: in ?k from
being confused with the ::: we introduced in the expansion of
generate-temporaries.

I don't know what the best exact syntax for this extension would be.
Here are several possibilities (using the conventions foo* == any
number of foo, and foo? == zero or one foo):

  -- Ellipsis choice before the literals, as above:
    (syntax-rules <ellipsis>? <literals> <rule>*)

  -- After the literals:
    (syntax-rules <literals> <ellipsis>? <rule>*)

  -- On a per-rule basis:
    (syntax-rules literals (<ellipsis>? <pattern> <template>) ...)

  -- After the literals, with an extra "noise word" (like cond's =>)
     to distinguish this from other syntax-rules extensions:
    (syntax-rules <literals> (ellipsis <ellipsis>)? <rule>*)

-al