7

如果我明确定义这样的函数(defn f [x] (get x "a")),那么两者都(-> {"a" 1} f)可以(f {"a" 1})按预期工作。

但是,如果我使用匿名函数,则只能(#(get % "a") {"a" 1})工作但(-> {"a" 1} #(get % "a"))会引发异常:CompilerException java.lang.ClassCastException: clojure.lang.PersistentArrayMap cannot \ be cast to clojure.lang.ISeq, compiling:(NO_SOURCE_PATH:1:1)

4

1 回答 1

12

#(get % "a")由读者扩展:

 user=> '#(get % "a")
 (fn* [p1__852#] (get p1__852# "a"))

在这种情况下,您可以忽略 fn 和 fn* 之间的区别。

(-> ...)是一个只重线程其参数的宏:

user=> (macroexpand-1 '(-> {"a" 1} f))
(f {"a" 1})

请注意,如果 f 还没有括号,它只会将括号括起来,所以:

user=> (macroexpand-1 '(-> {"a" 1} (f)))
(f {"a" 1})

fn但这在应用于宏时不会像您预期的那样工作:

user=> (macroexpand-1 '(-> {"a" 1} (fn [x] (get x "a"))))
(fn {"a" 1} [x] (get x "a"))

或在 #(...) 阅读器表单上:

user=> (macroexpand-1 '(-> {"a" 1} #(get % "a")))
(fn* {"a" 1} [p1__867#] (get p1__867# "a"))

一般的解决方案是将你的匿名函数放在一个列表中,但如果你可以使用命名函数,我认为它读起来更清晰:

user=> (macroexpand-1 '(-> {"a" 1} (#(get % "a"))))
((fn* [p1__870#] (get p1__870# "a")) {"a" 1})
于 2013-06-06T08:15:35.087 回答