Clojure:与fn有什么不同?

woo*_*ngs 7 clojure language-lawyer

如果我明确定义这样的功能(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)

Joo*_*aat 12

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

 user=> '#(get % "a")
 (fn* [p1__852#] (get p1__852# "a"))
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您可以忽略fn和fn*之间的差异.

(-> ...) 是一个只重新读取其参数的宏:

user=> (macroexpand-1 '(-> {"a" 1} f))
(f {"a" 1})
Run Code Online (Sandbox Code Playgroud)

请注意,如果没有括号,它只包括f周围的括号,所以:

user=> (macroexpand-1 '(-> {"a" 1} (f)))
(f {"a" 1})
Run Code Online (Sandbox Code Playgroud)

但是,当您应用于fn宏时,这将无法正常工作:

user=> (macroexpand-1 '(-> {"a" 1} (fn [x] (get x "a"))))
(fn {"a" 1} [x] (get x "a"))
Run Code Online (Sandbox Code Playgroud)

或#(...)读者表格:

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

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

user=> (macroexpand-1 '(-> {"a" 1} (#(get % "a"))))
((fn* [p1__870#] (get p1__870# "a")) {"a" 1})
Run Code Online (Sandbox Code Playgroud)