# Error: no pattern variables before ellipsis in template

**URL:** <https://racket.discourse.group/t/error-no-pattern-variables-before-ellipsis-in-template/2520>\
**Category:** Questions & Answers\
**Tags:** question, macro\
**Created:** [November 20, 2023, 3:14pm UTC](https://racket.discourse.group/t/error-no-pattern-variables-before-ellipsis-in-template/2520 "2023-11-20T15:14:07Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![ceving](https://avatars.discourse-cdn.com/v4/letter/c/a3d4f5/32.png) [@ceving](https://racket.discourse.group/u/ceving)\
**Post date:** [November 20, 2023, 3:14pm UTC](https://racket.discourse.group/t/error-no-pattern-variables-before-ellipsis-in-template/2520/1 "2023-11-20T15:14:07Z")

</div>

The following code throws the error:

> no pattern variables before ellipsis in template

I do not understand why `::f*` is no pattern variable. Can anybody explain?

```scheme
#lang racket

(define undefined (when #f #f))

(define print~s (lambda (args) (write (car args)) (cdr args)))
(define print~a (lambda (args) (display (car args)) (cdr args)))
(define mkprint (lambda (literal) (lambda (args) (display literal) args)))
(define print~~ (mkprint #\~))

(define-syntax :writer
  (syntax-rules (~s ~a ~~)
    ;; Simple formats
    ((_ ~s) print~s)
    ((_ ~a) print~a)
    ((_ ~~) print~~)
    ;; List format, which should behave like ~:{~} in CL
    ((_ (:f1 :f* ...))
     ;; Macro needs to be changed to add ~^ and early termination.
     (letrec-syntax ((::writer
                      (syntax-rules (~s ~a ~~ ~^)
                        ((_ ~^) (lambda (args) #f)) ;; return #f to stop
                        ((_ ~s) print~s)
                        ((_ ~a) print~a)
                        ((_ ~~) print~~)
                        ((_ ::*) (mkprint ::*))
                        ((_ ::f1 ::f2 ::f* ...)
                         (lambda (args)
                           (let ((interim ((::writer ::f1) args)))
                             (if interim
                                 ((::writer ::f2 ::f* ...) interim)
                                 '())))))))
       (lambda (args)
         (let loop ((args (car args)))
           (when (pair? args)
             (let ((arg (car args))
                   (args (cdr args)))
               ((::writer :f1 :f* ...) arg)
               (loop args))))
         (cdr args))))
    ;; Anyting else, which is not a format.
    ((_ :*) (mkprint :*))
    ;; Recursion
    ((_ :f1 :f2 :f* ...)
     (lambda (args)
       ((:writer :f2 :f* ...) ((:writer :f1) args))))))

#;((:writer ~a) '("a\n"))
#;((:writer ~s ~a) '("a" "\n"))
#;((:writer "a\n") '())
#;((:writer ~s (~a) "\n") '("a" ((1) (2) (3))))
((:writer (~a ~^ ",") #\newline) '(((1) (2))))

```

---

<div class="post-metadata">

**Author:** ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)\
**Post date:** [November 20, 2023, 3:45pm UTC](https://racket.discourse.group/t/error-no-pattern-variables-before-ellipsis-in-template/2520/2 "2023-11-20T15:45:32Z")

</div>

Short: You want `...` to appear in the output, so you need to quote it with `(... ...)`.

When you are writing macro generating macros there are two levels of ellipsis.  
The outer one, where you can write as `...` as normal and the inner one where you need to escape.

You can escape it with `(... ...)`. That looks odd to me, so I usually bind it to an identifier named `ooo`.

Silly example:

```scheme
#lang racket
(require (for-syntax syntax/parse
                     racket/syntax))

(define-syntax (make-id-macro stx)
  (syntax-parse stx
    [(_ id)
     (with-syntax ([name (format-id #'id "do-~a" #'id)]
                   [ooo #'(... ...)])

       #'(define-syntax (name stx)
           (syntax-parse stx
             [(_ parms ooo)
              #'(list parms ooo)])))]))

(make-id-macro foo)
(do-foo 1 2)

```

/Jens Axel

---

<div class="post-metadata">

**Author:** ![sorawee](https://avatars.discourse-cdn.com/v4/letter/s/ea5d25/32.png) [@sorawee](https://racket.discourse.group/u/sorawee)\
**Post date:** [November 20, 2023, 3:54pm UTC](https://racket.discourse.group/t/error-no-pattern-variables-before-ellipsis-in-template/2520/3 "2023-11-20T15:54:29Z")

</div>

> no pattern variables before ellipsis in template in: ::f\*

This is actually an error about ellipsis, not pattern variable per se.

In your code, there’s a `syntax-rules` inside another `syntax-rules`. When you write `...`, Racket gets confused about which `syntax-rules` should `...` be associated with.

It’s clear from your code that you meant to associate `...` in `::f* ...` with the inner `syntax-rules`. So you need to escape them by replacing these occurrences of `...` with `(... ...)` .

```scheme
#lang racket

(define undefined (when #f #f))

(define print~s (lambda (args) (write (car args)) (cdr args)))
(define print~a (lambda (args) (display (car args)) (cdr args)))
(define mkprint (lambda (literal) (lambda (args) (display literal) args)))
(define print~~ (mkprint #\~))

(define-syntax :writer
  (syntax-rules (~s ~a ~~)
    ;; Simple formats
    ((_ ~s) print~s)
    ((_ ~a) print~a)
    ((_ ~~) print~~)
    ;; List format, which should behave like ~:{~} in CL
    ((_ (:f1 :f* ...))
     ;; Macro needs to be changed to add ~^ and early termination.
     (letrec-syntax ((::writer
                      (syntax-rules (~s ~a ~~ ~^)
                        ((_ ~^) (lambda (args) #f)) ;; return #f to stop
                        ((_ ~s) print~s)
                        ((_ ~a) print~a)
                        ((_ ~~) print~~)
                        ((_ ::*) (mkprint ::*))
                        ((_ ::f1 ::f2 ::f* (... ...))
                         (lambda (args)
                           (let ((interim ((::writer ::f1) args)))
                             (if interim
                                 ((::writer ::f2 ::f* (... ...)) interim)
                                 '())))))))
       (lambda (args)
         (let loop ((args (car args)))
           (when (pair? args)
             (let ((arg (car args))
                   (args (cdr args)))
               ((::writer :f1 :f* ...) arg)
               (loop args))))
         (cdr args))))
    ;; Anyting else, which is not a format.
    ((_ :*) (mkprint :*))
    ;; Recursion
    ((_ :f1 :f2 :f* ...)
     (lambda (args)
       ((:writer :f2 :f* ...) ((:writer :f1) args))))))

#;((:writer ~a) '("a\n"))
#;((:writer ~s ~a) '("a" "\n"))
#;((:writer "a\n") '())
#;((:writer ~s (~a) "\n") '("a" ((1) (2) (3))))
((:writer (~a ~^ ",") #\newline) '(((1) (2))))

```

The above code now works.

---

<div class="post-metadata">

**Author:** ![ceving](https://avatars.discourse-cdn.com/v4/letter/c/a3d4f5/32.png) [@ceving](https://racket.discourse.group/u/ceving)\
**Post date:** [November 20, 2023, 4:05pm UTC](https://racket.discourse.group/t/error-no-pattern-variables-before-ellipsis-in-template/2520/4 "2023-11-20T16:05:42Z")

</div>

Thanks! It works now.

```scheme
#lang racket

(define undefined (when #f #f))

(define print~s (lambda (args) (write (car args)) (cdr args)))
(define print~a (lambda (args) (display (car args)) (cdr args)))
(define mkprint (lambda (literal) (lambda (args) (display literal) args)))
(define print~~ (mkprint #\~))

(define-syntax :writer
  (syntax-rules (~s ~a ~~)
    ;; Simple formats
    ((_ ~s) print~s)
    ((_ ~a) print~a)
    ((_ ~~) print~~)
    ;; List format, which should behave like ~:{~} in CL
    ((_ (:f1 :f* ...))
     ;; Macro needs to be changed for ~^ to terminate early.
     (letrec-syntax ((::writer
                      (syntax-rules (~s ~a ~~ ~^)
                        ((_ ::last ~^)
                         (lambda (args)
                           (if ::last
                               #f ;; stop here
                               args)))
                        ((_ ::last ~s) print~s)
                        ((_ ::last ~a) print~a)
                        ((_ ::last ~~) print~~)
                        ((_ ::last ::*) (mkprint ::*))
                        ((_ ::last ::f1 ::f2 ::f* (... ...))
                         (lambda (args)
                           (let ((interim ((::writer ::last ::f1) args)))
                             (if interim
                                 ((::writer ::last ::f2 ::f* (... ...)) interim)
                                 '())))))))
       (lambda (args)
         (let loop ((args (car args)))
           (when (pair? args)
             (let ((arg (car args))
                   (args (cdr args)))
               ((::writer (null? args) :f1 :f* ...) arg)
               (loop args))))
         (cdr args))))
    ;; Anyting else, which is not a format.
    ((_ :*) (mkprint :*))
    ;; Recursion
    ((_ :f1 :f2 :f* ...)
     (lambda (args)
       ((:writer :f2 :f* ...) ((:writer :f1) args))))))

#;((:writer ~a) '("a\n"))
#;((:writer ~s ~a) '("a" "\n"))
#;((:writer "a\n") '())
#;((:writer ~s (~a) "\n") '("a" ((1) (2) (3))))
((:writer #\{ (~s #\: ~s ~^ #\, #\space) #\} #\newline)
 '((("a" 1) ("b" 2) ("c" 3))))

```
