Zelphir Kaltstahl
Zelphir Kaltstahl

Reputation: 6189

Scheme macro what does match what?

From https://www.gnu.org/software/guile/manual/html_node/Syntax-Rules.html#Syntax-Rules I got the following macro example:

(define-syntax simple-let
  (syntax-rules ()
    ((_ (head ... ((x . y) val) . tail)
        body1 body2 ...)
     (syntax-error
      "expected an identifier but got"
      (x . y)))
    ((_ ((name val) ...) body1 body2 ...)
     ((lambda (name ...) body1 body2 ...)
      val ...))))

I am trying to understand how this macro works. So I annotated it a little:

;; EXAMPLE 7
;; Reporting errors at macro-expansion time (read time, compile time).
(define-syntax simple-let
  (syntax-rules ()
    [(simple-let (head ... ((x . y) val) . tail)
                                        ; (1) head ... can also be zero times?
                                        ; (2) what is `. tail` matching?
                                        ; (3) can I not use two ellipsis on the
                                        ; same level instead of `. tail`?
                 body1
                 body2 ...)
     (syntax-error "expected an identifier but got"
                   (x . y))]
    ;; if there ((a . b) val) is not matched
    [(simple-let ((name val) ...)
                 body1
                 body2 ...)
     ((lambda (name ...)
        body1
        body2 ...)
      val ...)]))

The only part I do not really understand in terms of how it works is the first match expression:

(simple-let (head ... ((x . y) val) . tail)

So I tried a few examples:

;; simply working
(simple-let ([a 3])
            (+ a 4))

;; caught
(simple-let ([(a . b) 3])  ; Q: What is `. tail` matching in this one?
            (+ a 4))
(simple-let ([a 3] [(b . c) 3])  ; Q: What is `. tail` matching in this one?
            (+ a b))

;; not caught
(simple-let ([a 3] [(b . c) 3] [d 4])  ; Q: Why is `. tail` not matching `[d 4]`?
            (+ a b))

I have difficulties understanding what part is . tail matching and why. I tried using ... instead of . and put it behind tail, in order to catch the example where the syntax error is not caught, because it does not go into the first match case, but it does not work and tells me that it is a bad usage of ellipsis. My guess is, that one cannot have two ellipsis in the same nesting level, because it would be hard to know which ellipsis matches what. Kind of like regular expressions become computationally expensive in some cases.

So what does . tail match in the examples and why is that one example not caught?

Upvotes: 1

Views: 95

Answers (1)

Stefan
Stefan

Reputation: 291

usually tail matches the rest of the list e.g.

for '(1 2 3 4) matching with the pattern (1 . x), x matches '(2 3 4).

The result is confusing so one need to go to the sources to see the implementaion (see ice-9/psyntax.scm)

There one can see that the ellipsis is translated to (each+ x y z) with z in this case is tail and is matching the last cdr which in all your cases is '().

In the example ... is gready and . tail is not. If you are dissatisfied with how this behavior is documented or want to change the implementation you may ask on the guile-devel mailing list: [email protected]

Guile has also syntax-parse as a downloadable lib (search for guile-syntax-parse) which is a port of racket's syntax-parse as of a couple of years ago (see racket's documentation if you are curious) I coded your example with syntax-parse and that seamed to execute as you expected.

Upvotes: 1

Related Questions