仅使用LISP原语定义defmacro函数?

时间:2010-08-21 02:02:37

标签: macros clojure lisp scheme primitive

McCarthy's基本S函数和谓词为atomeqcarcdrcons

然后他继续添加他的基本符号,以便能够写出他所谓的S函数:quotecondlambdalabel

在此基础上,我们将这些称为“LISP原语”(尽管我对类似谓词的论证持开放态度,如numberp

如何在您选择的LISP中仅使用这些原语来定义defmacro函数? (包括Scheme和Clojure)

2 个答案:

答案 0 :(得分:5)

尝试在像McCarthy的LISP机器这样的机器上执行此操作的问题在于,没有办法在运行时阻止参数评估,并且在编译时无法改变事物(这是宏执行的操作:他们在编译之前重新安排代码,基本上。)

但这并不能阻止我们在运行时在McCarthy的机器上重写我们的代码。诀窍是引用我们传递给我们的“宏”的参数,因此它们不会被评估。

作为一个例子,让我们看一下我们可能想要的功能; unless。我们的理论函数有两个参数pq,并返回q ,除非 p为真。如果p为真,则返回nil。

一些例子(在Clojure的语法中,但不会改变任何内容):

(unless (= "apples" "oranges") "bacon")
=> "bacon"

(unless (= "pears" "pears") "bacon")
=> nil

首先,我们可能希望将unless写为函数:

(defn unless [p q]
    (cond p nil
          true q))

这似乎工作正常:

(unless true 6)
=> nil

(unless false 6)
=> 6

对于麦卡锡的LISP,它可以正常工作。问题是我们现在不只是在现代Lisps中有无副作用的代码,所以传递给unless的所有参数都被评估,无论我们是否想要它们,都是有问题的。事实上,即使在McCarthy的LISP中,如果评估年龄要做的其中一个论点,这可能是一个问题,而我们只想很少这样做。但这特别是副作用的问题。

因此,如果unless为false,我们希望我们的q评估并仅返回p 。如果我们将qp作为参数传递给函数,我们就无法做到这一点。

但是在我们将它们传递给我们的函数之前我们可以quote它们,从而阻止了它们的评估。我们可以使用eval的功能(在我们需要的时候,也只使用参考文章后面的基元定义的基元和其他函数定义)来评估我们需要什么。

所以我们有一个新的unless

(defn unless [p q] 
    (cond (eval p) nil 
          true (eval q)))

我们使用它有点不同:

(unless (quote false) (quote (println "squid!")))
=> "squid" nil
(unless (quote true) (quote (println "squid!")))
=> nil

在那里你可以慷慨地称之为宏观。


但这不是defmacro或其他语言的等效词。那是因为在McCarthy的机器上,在编译时没有办法执行代码。如果您使用eval函数评估代码,则无法知道不将参数评估为“宏”函数。阅读和评估之间的区别与现在不同,尽管这个想法存在。在quote的酷炫和eval的列表操作中,“重写”代码的能力就在那里,但它并没有像现在这样用语言实习(我' d称它为语法糖,差不多:只引用你的论点,你就有了宏观系统的力量。)

我希望我已经回答了你的问题,而没有试图用自己的原语来定义一个体面的defmacro。如果你真的想看到这一点,我会指出你在Clojure来源中难以理解的source for defmacro,或者更多的Google。

答案 1 :(得分:2)

在其所有细节中完全解释它需要大量的空间和时间来回答这里,但是大纲非常简单。每个LISP最终都有一些类似于READ-EVAL-PRINT循环的东西,也就是说,逐个元素,逐个元素地解释它,并改变状态 - 在内存中或通过打印结果。

读取部分查看读取的每个元素并使用它执行某些操作:

(cond ((atom elem)(lambda ...))
      ((function-p elem) (lambda ...)))

要解释宏,你只需(?)需要实现一个函数,将宏的模板文本放在存储中的某个地方,这个repl循环的谓词 - 这意味着简单地定义一个函数 - 说“哦,这是一个宏!“,然后将该模板文本复制回阅读器,以便进行解释。

如果您真的想看到毛茸茸的细节,请阅读计算机程序的结构和解释或阅读Queinnec的Lisp in Small PIeces