在Clojure中,宏与函数有何不同?
我刚从宏开始,做了一个简单的宏来返回列表中的最大值在Clojure中,宏与函数有何不同?,clojure,Clojure,我刚从宏开始,做了一个简单的宏来返回列表中的最大值 (defmacro macro-max [list] (apply max list)) 如果我做一个函数来做同样的事情,它将是 (defn macro-max [list] (apply max list)) 我只是在探索Clojure,所以我知道的不多 专家们可能觉得我很傻,但看起来我几乎可以定义一个函数而不是一个宏。除非需要,否则当你不想评估你的参数时,区别就出现了 考虑这个例子: (defn unless [pred body]
(defmacro macro-max [list] (apply max list))
如果我做一个函数来做同样的事情,它将是
(defn macro-max [list] (apply max list))
我只是在探索Clojure,所以我知道的不多
专家们可能觉得我很傻,但看起来我几乎可以定义一个函数而不是一个宏。除非需要,否则当你不想评估你的参数时,区别就出现了 考虑这个例子:
(defn unless [pred body]
(when (not pred)
body))
这是行不通的,因为函数的参数需要求值。所以body始终运行,如下所示:
(unless (zero? 2)
(prn "Not zero!"))
;; "Not zero!"
(unless (zero? 0)
(prn "Not zero!"))
;; "Not zero!"
上面的两次执行都打印“不为零!”,这显然是错误的
除非使用宏,否则编写实用程序的唯一方法是:
(defmacro unless [pred body]
`(when (not ~pred)
~@body))
现在,如果我们尝试一下,我们将看到它按预期工作:
(unless (zero? 2)
(prn "Not zero!"))
;; "Not zero!"
(unless (zero? 0)
(prn "Not zero!"))
;; this prints nothing
宏仅在开发人员决定执行时才计算其参数
您将注意到宏中的一些特殊字符,如“、~和~@”。它们分别代表语法引号、unquote和unquote拼接,并进行了解释
我建议你研究一下这些符号
希望这有帮助。我没有宏方面的经验,但它可以让您通过函数扩展combilier。我不确定,但它是在运行时进行计算的。如果一个函数可以执行,那么请务必使用一个函数。Clojure库遵循这一规则,因此在那里定义的大多数宏可能无法真正表示为函数。以->
宏为例:
(->>
"abcdefghij"
(take 5)
(drop 3)
(apply str))
上述计算结果为“de”。函数无法做到这一点,因为宏的参数在自己求值时没有意义-(取5)
求值时会引发错误
宏所做的是在计算表单之前修改表单(通过插入上一个表达式作为表单的最后一个参数)。这是只有宏才能做的,而不是函数。宏是函数。区别仅在于计算时间(宏在宏展开时计算,这是编译过程中的一个步骤,函数在运行时计算)。此外,宏对S表达式起作用(因此宏有点像一个函数,您可以引用每个参数,也就是说,您可以轻松地将任何宏(mac a b)
替换为函数(fun'a'b)
如果你没有经验,而且不确定,你为什么要费心回答这个问题呢?认真地说。你的答案哪一部分回答了这个问题,哪怕只回答了1%?语法引号和不引号功能有时在宏之外也很有用。“你可以用函数轻松地替换任何宏(mac a b)
(fun'a'b)
”。绝对不容易。要做到这一点,a)函数需要在调用方的上下文中解析符号,或者b)调用方必须在自己的上下文中计算函数的结果。b)将更接近宏在现实中的工作方式。@RafałDowgird我说的是宏的作用。宏只作用于S表达式,而这正是“normal”函数所能做的。当涉及到“函数与宏”时,插入宏的结果来代替宏调用并不重要。