在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”函数所能做的。当涉及到“函数与宏”时,插入宏的结果来代替宏调用并不重要。