【发布时间】:2020-01-20 18:16:37
【问题描述】:
我目前正在将几乎所有 Scheme 实现都使用的 Alex Shinn's canonical implementation of match for Scheme 移植到另一个 Lisp。
我遇到了match-letrec 的一堵墙。在the simplified version of his implementation中,定义如下:
(define-syntax match-let
(syntax-rules ()
((_ ((pat expr)) . body)
(match expr (pat . body)))
((_ ((pat expr) ...) . body)
(match (list expr ...) ((pat ...) . body)))
((_ loop . rest)
(match-named-let loop () . rest))
))
(define-syntax match-letrec
(syntax-rules ()
((_ vars . body) (match-letrec-helper () vars . body))))
(define-syntax match-letrec-helper
(syntax-rules ()
((_ ((pat expr var) ...) () . body)
(letrec ((var expr) ...)
(match-let ((pat var) ...)
. body)))
((_ (v ...) ((pat expr) . rest) . body)
(match-letrec-helper (v ... (pat expr tmp)) rest . body))
))
下面是它在使用时的外观示例(Guile 1.8):
(match-letrec (((x y) (list 1 (lambda () (list a x))))
((a b) (list 2 (lambda () (list x a)))))
(append (y) (b))
=> (2 1 1 2)
我很难理解这实际上是如何工作的。当我手动将其扩展到match 时,我得到以下代码(#{g...} 指示的自动符号):
(letrec ((#{g1} (list 1 (lambda () (list a x))))
(#{g2} (list 2 (lambda () (list x a)))))
(match (list #{g1} #{g2}) (((x y) (a b)) (append (y) (b))))
自动符号由match-letrec-helper 的第二条规则中的tmp 替换生成。这种扩展意味着 lambda 表达式在 x 和 a 绑定之前进行评估,因此无法捕获它们。
有人能解释一下这个语法应该如何正确扩展吗?我错过了什么?
【问题讨论】:
-
这在 Racket 7.4、Chicken 4.13 或 Guile 2.2.4 中都不起作用。它看起来也不像您链接到的实现。
-
谢谢。我已经更新了这个问题,以澄清我在这个问题中引用了 Alex Shinn 匹配器的简化版本,以便说明清楚,并添加了一个链接。我将构建最新的 Guile 并看看。
标签: macros pattern-matching scheme metaprogramming