在这个例子中避免宏是好的吗?

时间:2015-07-02 17:22:23

标签: clojure

我读过那些数据>功能>宏

假设您想以后缀方式评估代码。

哪种方法会更好?

;; Macro

(defmacro reverse-fn [expression]
  (conj (butlast expression) (last expression)))

(reverse-fn ("hello world" println))
; => "hello world"


;; Function and data

(def data ["hello world" println])

(defn reverse-fn [data] 
  (apply (eval (last data)) (butlast data)))

(reverse-fn ["hello world" println])
; => "hello world"

谢谢!

4 个答案:

答案 0 :(得分:1)

如果您对代码中的任何类型的数据需要不同的评估行为,那么您最好选择,因为它们可以在编译时将未评估的数据转换为您想要评估的代码。

  

Clojure有一个编程宏系统,允许编译器通过用户代码进行扩展。宏可用于定义句法结构,这些结构需要原语或其他语言的内置支持。 (http://clojure.org/macros

您提供的示例明确具有该要求(“以后缀方式评估代码”),这就是宏是正确选择的原因。

答案 1 :(得分:0)

一般来说:

然而,宏使用它们;宏在遇到它们时会扩展,因此您将在结果字节代码中内联一个或多个代码块。它们是封装高阶DSL术语的理想选择。

另一方面,函数非常适合重用,您可以在本地化函数的纯度,并且可以从多个其他函数调用它,而不会增加代码占用空间。它们非常适合本地化或全球使用。

REPL行为考虑:单个函数更容易返工,而不必担心完全评估整个源文件以确保所有宏引用扩展都得到更新。

希望这有帮助

答案 2 :(得分:0)

简单的规则是最好的:如果可以的话,使用一个函数,如果必须的话,使用宏。

答案 3 :(得分:0)

你的宏比你的功能更好:宏比使用eval的函数更好。

但是,该功能无需使用eval。你可以写它

(defn reverse-fn [data] 
  (apply (last data) (butlast data)))

然后,例如,和以前一样,

(reverse-fn [3 inc])
=> 4

在相关主题上,您可能会发现this explanation传感器很有趣。

编辑:

请注意,函数是文字,在函数评估自身的意义上:

((eval +) 1 1)
=>  2