尝试在像McCarthy的LISP机器这样的机器上执行此操作的问题在于,没有办法在运行时阻止参数评估,并且在编译时无法改变事物(宏是这样做的:它们重新排列代码在它编译之前,基本上).
但这并不能阻止我们在运行时在McCarthy的机器上重写我们的代码.诀窍是引用我们传递给我们的"宏"的参数,因此它们不会被评估.
作为一个例子,让我们看看我们可能想要的功能; unless.我们的理论函数有两个参数,p并且q,q 除非 p是真的,否则返回.如果p是,则返回nil.
一些例子(在Clojure的语法中,但不会改变任何东西):
(unless (= "apples" "oranges") "bacon")
=> "bacon"
(unless (= "pears" "pears") "bacon")
=> nil
Run Code Online (Sandbox Code Playgroud)
所以一开始我们可能想写unless一个函数:
(defn unless [p q]
(cond p nil
true q))
Run Code Online (Sandbox Code Playgroud)
这似乎工作得很好:
(unless true 6)
=> nil
(unless false 6)
=> 6
Run Code Online (Sandbox Code Playgroud)
而对于McCarthy的LISP,它可以正常工作.问题是我们现在不只是在现代Lisps中有无副作用的代码,所以传递给所有参数的事实unless是否被评估,无论我们是否想要它们,都是有问题的.事实上,即使在麦卡锡的LISP中,如果评估其中一个论点需要花费很长时间才能完成,这可能是一个问题,我们只想做很少的事情.但这特别是副作用的问题.
因此,我们希望我们的unless评估,并返回q 唯一的,如果p是假的.如果我们传递q和p作为函数的参数,我们就不能这样做.
但是quote在我们将它们传递给我们的函数之前我们就可以了 我们可以使用eval(在参考文章后面仅使用原语和其他函数定义的原语和定义的功能)来评估我们需要的时间.
所以我们有一个新的unless:
(defn unless [p q]
(cond (eval p) nil
true (eval q)))
Run Code Online (Sandbox Code Playgroud)
我们使用它有点不同:
(unless (quote false) (quote (println "squid!")))
=> "squid" nil
(unless (quote true) (quote (println "squid!")))
=> nil
Run Code Online (Sandbox Code Playgroud)
在那里你可以慷慨地称之为宏观.
但这不是defmacro或等同于其他语言.那是因为在McCarthy的机器上,在编译时没有办法执行代码.如果您使用该eval函数评估代码,则无法知道不将参数计算为"宏"函数.阅读和评估之间的区别与现在不同,尽管这个想法存在."重写"代码的能力就在那里,在酷quote和与列表操作相结合的情况下eval,但它并没有像现在那样用语言实现(我称它为语法糖,差不多:只是引用你的论点,你已经掌握了宏观系统的力量.)
我希望我已经回答了你的问题,而没有试图defmacro用自己的原语定义一个体面的东西.如果你真的想看到的是,我会点你到难以神交源defmacro在Clojure的来源,或者周围的一些更多的谷歌.
| 归档时间: |
|
| 查看次数: |
1355 次 |
| 最近记录: |