一个人可以安全地忽略宏和内置之间的区别吗?

7

我刚开始学习Clojure,这也是我第一次接触Lisp语言。显然有很多需要掌握的知识点,为了减轻认知负担,我试图找出哪些部分可以暂时忽略。

对于宏表达式和内置表达式,我们可以安全地将它们视为同等重要吗?还是会遇到潜在的问题呢?

换句话说,我是否会遇到需要知道 (defn f1 []) 展开成什么形式的情况?

(def f1 (.withMeta (clojure.core/fn f1 ([])) (.meta (var f1))))
3个回答

10

宏通常组合方式完全不同。宏不是“头等公民”:您不能将它们传递给map等函数,也无法将其存储在变量中或将其应用于参数列表。最初您不需要担心这些问题,因为它们显然无法工作:一个微妙且难以检测的错误会带来更大的麻烦。如果您尝试运行它们,则会出现这样的错误。

(map if [true false true false] [1 2 3 4] [-1 -2 -3 -4])

如果if语句不是一个函数,这一点将非常明显。只需记住宏不是函数,你就会没问题 :)

PS: 宏是(fn (fn (fn :-D) :^P) :O)


谢谢,我没有考虑到无意中将宏传递给高阶函数。 - JimB
3
这似乎是在回应与原帖关切相反的问题:你正在区分(a)宏和特殊形式,以及(b)函数。特殊形式和宏都不能作为参数传递给像map这样的高阶函数; 他问的是是否有任何方式使特殊形式与宏有意义上的不同。 - amalloy
"if is not a function" 中的 "if" 应该放在代码块中。 - J. Mini

8

在几乎所有情况下,您可以完全忽略这种区别。(实际上,您已经这样做了,因为fn也不是内置的,它是一个扩展到fn*的宏)

我遇到的唯一例外是,如果您尝试重新定义宏和内置函数,它们会有不同的行为。只要不重新定义任何现有功能,您就可以将它们视为相同。


1

我自己也是一个Clojure新手,但花了更多时间尝试这种语言。

我可以说Clojure内置的宏非常安全,因为你甚至可以在不知道它们是宏的情况下使用它们。

特别是因为Clojure比Common Lisp更注重不可变性,所以很难因为宏的错误行为而导致bug。

所以,不,你不会遇到需要了解内置宏内部工作原理的情况。但如果你想弄清楚自己定制宏的内部工作原理,总有macroexpand可以帮助你。


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