Mar*_*rcs 1 dictionary exception clojure
我正在搞乱Clojure地图,我发现了这种我无法理解的情况.
假设我有一张这样的地图:
(def map-test {:name "head" :size 3})
Run Code Online (Sandbox Code Playgroud)
我想更改此映射的值,在Clojure中,通常的方法是使用修改后的数据生成新的映射.
所以我有这个功能:
(defn map-change
[part]
{:name (str (:name part) "-" 1) :size (:size part)})
Run Code Online (Sandbox Code Playgroud)
正如预期的那样,调用(map-change map-test)
返回:{:name "head-1", :size 3}
所以我编写了这个函数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))))
Run Code Online (Sandbox Code Playgroud)
但我得到一个例外,当我打电话时我无法理解(repeat-test map-test 5)
:
Wrong number of args (0) passed to: PersistentArrayMap
:size
在评估之后将值分配给右边时,调试器会抛出此异常(:size part)=>3
这是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
....
Run Code Online (Sandbox Code Playgroud)
但是,如果我使用非匿名函数执行与匿名函数相同的操作:
(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))))
Run Code Online (Sandbox Code Playgroud)
现在打电话(repeat-test map-test 5)
工作.为什么?我错过了什么?
该错误类似于此简化示例:
(map #({:a %}) [1 2 3])
clojure.lang.ArityException: Wrong number of args (0) passed to: PersistentArrayMap
Run Code Online (Sandbox Code Playgroud)
您可以展开#({:a %})
以查看实际编译和执行的代码:
(macroexpand '#({:a %}))
;;=> (fn* [p1__21110#] ({:a p1__21110#}))
Run Code Online (Sandbox Code Playgroud)
换句话说,#({:a %})
扩展到类似的东西(fn [x] ({:a x}))
.这个函数体中的问题是map被称为函数,没有参数.
地图的行为类似于功能:它们是键的功能.但他们期望至少有一个论点,最多两个:
({:a 1} :a) ;;=> :a
({:a 1} :b 2) ;;=> 2
Run Code Online (Sandbox Code Playgroud)
您根本不打算将地图称为功能.你只是想拥有地图.匿名函数文字总是扩展为函数调用,不能产生直接值.您可以通过以下几种方式解决:
#(-> {:a %})
#(identity {:a %})
#(hash-map :a %)
#(do {:a %})
(fn [x] {:a x})
我更喜欢后者,虽然我发现第一个非常有趣.这就像是说:我想要归还我指向的东西.