[英]Exception using map and anonymous functions in Clojure
I was messing around with Clojure maps and I discovered this situation that I can't understand. 我在弄乱Clojure地图,发现这种情况我无法理解。
Let's say I got a map like this: 假设我有一个这样的地图:
(def map-test {:name "head" :size 3})
I want to change the value of this map, in Clojure the usual way is to generate a new one with the modified data. 我想更改此地图的值,在Clojure中,通常的方法是使用修改后的数据生成一个新地图。
So I have this function: 所以我有这个功能:
(defn map-change
[part]
{:name (str (:name part) "-" 1) :size (:size part)})
As expected the invocation (map-change map-test)
returns: {:name "head-1", :size 3}
如预期的那样,调用
(map-change map-test)
返回: {:name "head-1", :size 3}
So I wrote this function using map
to clone the hash-map a given number of times, like this {:name "head-1" ...}{:name "head-2" ...}{:name "head-3" ...}
etc: 因此,我使用
map
编写了此函数,以将哈希map
克隆给定次数,例如{:name "head-1" ...}{:name "head-2" ...}{:name "head-3" ...}
等:
(defn repeat-test
[part times]
(map #({:name (str (:name part) "-" %) :size (:size part)}) (range 1 (inc times))))
But I got an exception that I cannot understand when I call (repeat-test map-test 5)
: 但是我打电话时遇到了一个我无法理解的异常
(repeat-test map-test 5)
:
Wrong number of args (0) passed to: PersistentArrayMap
The debugger throws this exception when is assigning the value to :size
right after has evaluated (:size part)=>3
在评估
(:size part)=>3
之后立即将值分配给:size
时,调试器将引发此异常。
Here's the last part of the stacktrace: 这是堆栈跟踪的最后一部分:
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
....
But if I use a non anonymous function that does the same operation as the anonymous one: 但是,如果我使用的非匿名函数执行的操作与匿名函数相同:
(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))))
Now calling (repeat-test map-test 5)
works. 现在调用
(repeat-test map-test 5)
。 Why ? 为什么呢 What am I missing ?
我想念什么?
The error is similar to this simplified example: 该错误类似于以下简化示例:
(map #({:a %}) [1 2 3])
clojure.lang.ArityException: Wrong number of args (0) passed to: PersistentArrayMap
You can expand #({:a %})
to see what code is actually being compiled and executed: 您可以展开
#({:a %})
来查看实际正在编译和执行的代码:
(macroexpand '#({:a %}))
;;=> (fn* [p1__21110#] ({:a p1__21110#}))
In other words, #({:a %})
expands to something like (fn [x] ({:ax}))
. 换句话说,
#({:a %})
扩展为类似(fn [x] ({:ax}))
。 The problem in the body of this function is that the map is called as a function, with no arguments. 该函数主体中的问题在于,该映射被称为没有参数的函数。
Maps behave like functions: they are functions of their keys. 地图的行为类似于功能:它们是键的功能。 But they expect at least one argument and at most two:
但是他们希望至少有一个论点,最多有两个:
({:a 1} :a) ;;=> :a
({:a 1} :b 2) ;;=> 2
You didn't intend to call the map as a function at all. 您根本不打算将地图作为一个函数来调用。 You just wanted to have the map.
您只想拥有地图。 The anonymous function literal always expands into a function call and cannot yield a direct value.
匿名函数文字总是扩展为函数调用,并且不能产生直接值。 You can solve this several ways:
您可以通过以下几种方法解决此问题:
#(-> {:a %})
#(identity {:a %})
#(hash-map :a %)
#(do {:a %})
(fn [x] {:ax})
I prefer the latter, although I find the first one pretty funny. 我更喜欢后者,尽管我发现第一个很有趣。 It's like saying: I want to return the thing I'm pointing at.
就像在说:我想退回我所指的东西。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.