【发布时间】:2014-04-26 18:42:48
【问题描述】:
考虑以下函数
(defn shove [data fun] (eval `(-> ~data ~fun)))
这里按预期工作
(shove [1 2 3] count) ;; ~~> 3
甚至在这里,它预计会失败,因为它评估(count) 太早了
(shove [1 2 3] (count))
;; ~~> clojure.lang.Compiler$CompilerException: clojure.lang.ArityException:
;; Wrong number of args (0) passed to: core$count, compiling:(null:5:1)
但是在这里,当我定义一个显式的 form 并将其作为数据传递给函数时,一切都很好:
(def move '(count))
(shove [1 2 3] move) ;; ~~> 3
现在,为了摆脱对eval 的显式调用,我尝试
(defmacro shovem [data form] `(-> ~data ~form))
效果很好
(shovem [1 2 3] count) ;; ~~> 3
(shovem [1 2 3] (count)) ;; ~~> 3
但它现在在显式定义的表单 move 上意外失败,并出现错误提示它评估 move 以获取 (count),然后继续尝试评估 (count),但方式与以前不同.
(shovem [1 2 3] move)
;; ~~> java.lang.ClassCastException:
;; clojure.lang.PersistentList cannot be cast to clojure.lang.IFn
我对这个错误消息感到困惑,我不知道如何获得所需的行为,即shovem 应该适用于所有三种输入,像count 这样的裸函数,像这样的括号函数形式(count),以及像 move 这样评估为此类形式的数据对象。
我可以在函数版本中使用eval,但是,此时我意识到我不明白发生了什么,我想完成练习以提高我的理解。
【问题讨论】:
-
尝试
macroexpand看看你的宏调用实际生成了什么