代码之家  ›  专栏  ›  技术社区  ›  Zelphir Kaltstahl

方案宏什么匹配什么?

  •  1
  • Zelphir Kaltstahl  · 技术社区  · 6 年前

    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 ,以便捕获未捕获语法错误的示例,因为它不进入第一个匹配大小写,但不起作用,并告诉我它是省略号的错误用法。我的猜测是,在同一嵌套级别中不能有两个省略号,因为很难知道哪个省略号匹配什么。在某些情况下,类似于正则表达式的计算成本会很高。

    那么做什么呢 . 尾 在示例中匹配,为什么没有捕获到该示例?

    1 回复  |  直到 6 年前
        1
  •  1
  •   Stefan    6 年前

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

    与图案(1)匹配的'(1 2 3 4)。x),x匹配'(2 3 4)。

    结果是令人困惑的,所以我们需要到资源处去查看实现(参见ice-9/psyntax.scm)

    在这里,可以看到省略号被翻译为(每个+x y z)with z,在本例中,它是tail,并且与最后一个cdr相匹配,在所有情况下,它都是')。

    在这个例子中…是伟大的和。尾巴不是。如果您对这种行为的记录方式不满意,或者希望更改实现方式,您可以在guile-devel邮件列表上询问:guile-devel@gnu.org

    Guile还提供了语法分析作为可下载的lib(搜索guile语法分析),这是Racket语法分析的一个端口,从几年前开始(如果您感兴趣,请参阅Racket的文档),我用语法分析对您的示例进行了编码,并按照您的预期进行了缝合。