【问题标题】:Is it good to avoid macro in this example?在这个例子中避免使用宏好吗?
【发布时间】:2015-07-02 17:22:22
【问题描述】:

我读取了该数据 > 函数 > 宏

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

哪种方法更好?

;; 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"

谢谢!

【问题讨论】:

    标签: clojure


    【解决方案1】:

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

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

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

    【讨论】:

      【解决方案2】:

      您的宏优于您的函数:宏优于使用eval 的函数。

      但是,该函数不需要使用eval。你可以写它

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

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

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

      在相关主题中,您可能会发现 this explanation of 转换器很有趣。


      编辑:

      请注意,函数是字面量,即函数对自身求值:

      ((eval +) 1 1)
      =>  2
      

      【讨论】:

        【解决方案3】:

        一般:

        然而,宏有其用处;宏在遇到它们时会展开,因此您将在生成的字节码中内联一个或多个代码块。它们非常适合封装高阶 DSL 术语。

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

        REPL 行为注意事项:单个函数更容易返工,而无需担心全面评估整个源文件以确保所有宏引用扩展都得到更新。

        希望对你有帮助

        【讨论】:

          【解决方案4】:

          简单的规则是最好的:尽可能使用函数,如果必须使用宏。

          【讨论】:

            猜你喜欢
            • 2014-09-12
            • 2010-11-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-06-03
            • 2012-06-02
            • 1970-01-01
            相关资源
            最近更新 更多