Exception using map and anonymous functions in Clojure
我在弄乱Clojure地图,发现这种情况我无法理解。
比方说我有一张这样的地图:
1 | (def map-test {:name"head" :size 3}) |
我想更改此地图的值,在Clojure中,通常的方法是使用修改后的数据生成一个新地图。
所以我有这个功能:
1 2 3 | (defn map-change [part] {:name (str (:name part)"-" 1) :size (:size part)}) |
按预期,调用
因此,我使用
1 2 3 | (defn repeat-test [part times] (map #({:name (str (:name part)"-" %) :size (:size part)}) (range 1 (inc times)))) |
但是当我呼叫
在评估
之后立即将值分配给
这是堆栈跟踪的最后一部分:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | Unhandled clojure.lang.ArityException Wrong number of args (0) passed to: PersistentArrayMap AFn.java: 429 clojure.lang.AFn/throwArity AFn.java: 28 clojure.lang.AFn/invoke REPL: 80 clj-lab-00.hobbits/repeat-test/fn core.clj: 2644 clojure.core/map/fn LazySeq.java: 40 clojure.lang.LazySeq/sval LazySeq.java: 49 clojure.lang.LazySeq/seq RT.java: 521 clojure.lang.RT/seq core.clj: 137 clojure.core/seq core_print.clj: 46 clojure.core/print-sequential core_print.clj: 153 clojure.core/fn core_print.clj: 153 clojure.core/fn MultiFn.java: 233 clojure.lang.MultiFn/invoke core.clj: 3572 clojure.core/pr-on core.clj: 3575 clojure.core/pr core.clj: 3575 clojure.core/pr AFn.java: 154 clojure.lang.AFn/applyToHelper .... |
但是如果我使用的非匿名函数执行与匿名函数相同的操作:
1 2 3 4 5 6 7 | (defn map-change [part i] {:name (str (:name part)"-" i) :size (:size part)}) (defn repeat-test [part times] (map #(map-change part %1) (range 1 (inc times)))) |
现在调用
该错误类似于此简化示例:
1 2 3 | (map #({:a %}) [1 2 3]) clojure.lang.ArityException: Wrong number of args (0) passed to: PersistentArrayMap |
您可以展开
1 2 | (macroexpand '#({:a %})) ;;=> (fn* [p1__21110#] ({:a p1__21110#})) |
换句话说,
地图的行为类似于功能:它们是键的功能。但是他们期望至少一个论点,最多两个论点:
1 2 | ({:a 1} :a) ;;=> :a ({:a 1} :b 2) ;;=> 2 |
您根本不打算将地图作为函数来调用。您只想拥有地图。匿名函数文字总是扩展为函数调用,并且不能产生直接值。您可以通过以下几种方法解决此问题:
-
#(-> {:a %}) -
#(identity {:a %}) -
#(hash-map :a %) -
#(do {:a %}) -
(fn [x] {:a x})
我更喜欢后者,尽管我发现第一个很有趣。就像在说:我要退还我指向的东西。