在Common Lisp中是否可以定义一个syntax-rules宏?

4
我了解到在Scheme中使用可以轻松定义小型宏。 是否有可能定义一个宏,其返回的列表可以被Common Lisp中的读取?
可能会像这样工作:
(defmacro and (&rest rest)
  (syntax-rules (rest) ()
    ((_)         t)
    ((_ x)       x
    ((_ x y)     (if x (if y y nil) nil))
    ((_ x y ...) (if x (and y ...) nil))))

请点击这里 - Barmar
2
为什么不可能呢?这只是模式匹配。 - Barmar
@Barmar 这样的宏需要了解词法绑定,但boundp只适用于全局变量。你不会知道哪个变量要gensym,哪个引用词法绑定。 - Sylwester
2
是的,使其具有卫生性是一个单独的问题。 - Barmar
1个回答

5

Tim Bradshaw的destructuring-match旨在使宏中的这种模式匹配变得容易:它是casedestructuring-bind的组合,因此每个子句的键具有解构lambda列表的语法。 Common Lisp还有其他几种模式匹配系统,但这个系统明确针对编写宏而设计:它不是一个通用的数据结构匹配工具,只是destructuring-bind的一般化版本。

它附带了一个小例子宏(它本身使用destructuring-match编写,并扩展到使用into的内容,该内容也使用destructuring-match!)称为define-matching-macro,您可以在其中编写一个名为etand版本。我认为以下两个宏是正确的,但我没有仔细考虑过。

(define-matching-macro et
  "This is meant to be AND"
  ((_) 't)
  ((_ x) x)
  ((_ x . more ) `(if ,x (et ,@more) nil)))

你也可以在普通的defmacro宏中使用destructuring-match。 在这里,我没有使用&whole来获取整个形式,所以我们不必烦恼表单的car。
(defmacro et (&rest forms)
  "This is also meant to be AND"
  (destructuring-match forms
    (() 't)
    ((x) x)
    ((x . more) `(if ,x (et ,@more) nil))))

注:

  • destructuring-match 使用符号名称为 "_" 的符号作为空白符,就像 Scheme 一样,因此您不需要声明它们被忽略,它们彼此都是不同的,实际上您可能在子句的正文中不引用它们;但它并不像 Scheme 的 x ... 那样,所以您只需要使用点 lambda 列表或 &rest 或您喜欢的任何东西;
  • 这些不是卫生宏,它们只是模式匹配宏;
  • 这些比您的示例要简单一些,但我认为它们已经足够了;
  • 您的宏实际上并不安全,因为 (if x x nil),除了多余之外(它只是 x),还可能评估两次 x,这是不安全的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接