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

haw*_*eye 11 lisp macros primitive scheme clojure

麦卡锡的基本S函数和谓语atom,eq,car,cdr,cons

接着,他添加到他的基本符号,以便能够写他所谓的S-功能:quote,cond,lambda,label

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

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

Isa*_*aac 5

尝试在像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是假的.如果我们传递qp作为函数的参数,我们就不能这样做.

但是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的来源,或者周围的一些更多的谷歌.