【问题标题】:How does the canonical match-letrec implementation work?规范的 match-letrec 实现如何工作?
【发布时间】: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 表达式在 xa 绑定之前进行评估,因此无法捕获它们。

有人能解释一下这个语法应该如何正确扩展吗?我错过了什么?

【问题讨论】:

  • 这在 Racket 7.4、Chicken 4.13 或 Guile 2.2.4 中都不起作用。它看起来也不像您链接到的实现。
  • 谢谢。我已经更新了这个问题,以澄清我在这个问题中引用了 Alex Shinn 匹配器的简化版本,以便说明清楚,并添加了一个链接。我将构建最新的 Guile 并看看。

标签: macros pattern-matching scheme metaprogramming


【解决方案1】:

你的例子

(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-letrec (((x y) (list 1 (lambda () (list a x))))
               ((a b) (list 2 (lambda () (list x a)))))
  (append (y) (b)))
. match: syntax error in pattern in: ((x y) (a b))

即使是 match-let 也不起作用

> (match-let (((x y) (list 1 2)))
    x)
. match: syntax error in pattern in: (x y)

解决方法如下:

(define-syntax match-let
  (syntax-rules (list)
    ((_ ((pat expr)) . body)
     (match expr (pat . body)))
    ((_ ((pat expr) ...) . body)
     (match (list expr ...) ((pat ...) . body)))
    ((_ loop . rest)
     (match-named-let loop () . rest))
    ))

现在你可以这样做了:

> (match-let (((list x y) (list 1 2)))
    (list x y))
'(1 2)

letrec 仍然无法正常工作

> (match-letrec (((list x y) (list 1 (lambda () (list a x))))
                 ((list a b) (list 2 (lambda () (list x a)))))
  (append (y) (b)))
. match: syntax error in pattern in: ((list x y) (list a b))

但这应该让您更接近一步,一旦您了解这些更改,请随时使用工作代码示例提出一个新问题。

【讨论】:

    猜你喜欢
    • 2012-01-18
    • 2010-10-10
    • 1970-01-01
    • 2018-11-01
    • 1970-01-01
    • 2018-06-30
    • 1970-01-01
    • 2014-02-21
    • 1970-01-01
    相关资源
    最近更新 更多