Clojure:defn和fn有什么不同?

Clojure:defn和fn有什么不同?,clojure,language-lawyer,Clojure,Language Lawyer,如果我明确定义这样的函数(defn f[x](get x“a”), 然后(>{“a”1}f)和(f{“a”1})都按预期工作 但是,如果我使用的是匿名函数,则只有(#(get%“a”){“a”1}有效,而({“a”1}(get%“a”)抛出异常:编译器异常java.lang.ClassCastException:clojure.lang.PersistentArrayMap无法\ 被转换到clojure.lang.ISeq,编译:(无源路径:1:1)(get%“a”)由读者展开: user=&

如果我明确定义这样的函数
(defn f[x](get x“a”)
, 然后
(>{“a”1}f)
(f{“a”1})
都按预期工作

但是,如果我使用的是匿名函数,则只有
(#(get%“a”){“a”1}
有效,而
({“a”1}(get%“a”)
抛出异常:
编译器异常java.lang.ClassCastException:clojure.lang.PersistentArrayMap无法\
被转换到clojure.lang.ISeq,编译:(无源路径:1:1)
(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})