Scheme macro 什么匹配什么?

Scheme macro what does match what?

https://www.gnu.org/software/guile/manual/html_node/Syntax-Rules.html#Syntax-Rules我得到了以下宏示例:

(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 ...))))

我想了解这个宏是如何工作的。所以我稍微注释了一下:

;; 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 ...)]))

就其工作原理而言,我唯一不太了解的部分是第一个匹配表达式:

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

所以我试了几个例子:

;; 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))

我很难理解 . tail 匹配的部分及其原因。我尝试使用 ... 而不是 . 并将其放在 tail 后面,以捕获未捕获语法错误的示例,因为它不会进入第一个匹配案例,但它不起作用,并告诉我这是省略号的错误用法。我的猜测是,在同一嵌套级别中不能有两个省略号,因为很难知道哪个省略号匹配什么。有点像正则表达式在某些情况下会变得计算量大。

那么 . tail 在示例中匹配了什么,为什么没有捕获到一个示例?

通常尾部匹配列表的其余部分,例如

对于匹配模式 (1 . x) 的 '(1 2 3 4),x 匹配 '(2 3 4)。

结果令人困惑,因此需要查看源代码以查看实现(参见 ice-9/psyntax.scm)

可以看到省略号被转换为 (each+ x y z),在这种情况下 z 是尾巴并且匹配最后一个 cdr,在所有情况下都是 '()。

在示例中...已经准备好并且。尾巴不是。如果您对这种行为的记录方式不满意或想更改实现方式,您可以在 guile-devel 邮件列表中提问:guile-devel@gnu.org

Guile 也有 syntax-parse 作为可下载的库(搜索 guile-syntax-parse),它是几年前球拍的 syntax-parse 的一个端口(参见球拍的文档如果你好奇的话)我用 syntax-parse 对你的例子进行了编码,并且按照你的预期执行。