在Clojure中,宏如何与函数不同?

时间:2013-04-15 06:34:57

标签: clojure

我刚刚开始使用宏并制作一个简单的宏来从列表中返回最大数字。

(defmacro macro-max [list] (apply max list))

如果我做了一个相同的功能,那就是。

(defn  macro-max [list] (apply max list))

我正在探索Clojure,所以我不太了解。

我可能对专家听起来很傻,但看起来我几乎可以定义一个函数而不是宏。

4 个答案:

答案 0 :(得分:7)

除非需要,否则当你不想评估你的论点时,这种差异就会变得生动。

考虑这个例子:

(defn unless [pred body]
  (when (not pred)
    body))

这不起作用,因为热切地评估函数的参数。所以身体总是运行,如下所示:

(unless (zero? 2)
        (prn "Not zero!"))
;; "Not zero!"

(unless (zero? 0)
        (prn "Not zero!"))
;; "Not zero!"

上述两个执行都打印出“非零!”,这显然是错误的。

编写unless实用程序的唯一方法是使用宏:

(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

宏只在开发人员决定时评估其参数。

您会注意到宏中的一些特殊字符,例如`,〜和〜@。它们分别代表语法引用,非引用和非引用拼接,并解释为here

我建议你研究这些符号。

希望这有帮助。

答案 1 :(得分:1)

如果一个函数可以做,那么一定要使用一个函数。 Clojure库遵循这个规则,因此可能大多数定义的宏不能真正表达为函数。拿->>宏:

(->> 
   "abcdefghij"
   (take 5)
   (drop 3)
   (apply str))

以上评估为“de”。函数无法做到这一点,因为宏的参数在自己进行求值时没有意义 - (take 5)在求值时会引发错误。

宏所做的是在评估之前修改表单(通过插入前一个表达式作为表单的最后一个参数。)这只是一个宏可以做的,而不是一个函数。

答案 2 :(得分:1)

宏是功能。区别仅在于评估时间(在宏扩展时评估宏,这是编译中的一个步骤,在运行时评估函数)。此外,宏工作在S-Expressions上(因此宏有点像你引用每个参数的函数,即你可以用函数(mac a b)轻松替换任何宏(fun 'a 'b)

答案 3 :(得分:-5)

我没有使用宏的经验,但它可以让你通过你的功能扩展梳理。我不确定,但它是在运行时进行评估的。