我在玩Clojure地图,我发现了一个我无法理解的情况。
假设我有张这样的地图:
(def map-test {:name "head" :size 3})我想改变这个映射的值,在Clojure中,通常的方法是用修改过的数据生成一个新的映射。
所以我有这样的功能:
(defn map-change
[part]
{:name (str (:name part) "-" 1) :size (:size part)})正如预期的那样,调用(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))))但当我打电话给(repeat-test map-test 5)时,我发现了一个无法理解的例外
Wrong number of args (0) passed to: PersistentArrayMap
当将值赋值给:size时,调试器将抛出此异常。
下面是堆栈跟踪的最后一部分:
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
....但是,如果我使用一个与匿名函数相同的非匿名函数:
(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))))现在,调用(repeat-test map-test 5)可以工作。为什么?我错过了什么?
发布于 2016-10-08 21:12:03
该错误类似于这个简化的示例:
(map #({:a %}) [1 2 3])
clojure.lang.ArityException: Wrong number of args (0) passed to: PersistentArrayMap您可以展开#({:a %}),查看实际正在编译和执行的代码:
(macroexpand '#({:a %}))
;;=> (fn* [p1__21110#] ({:a p1__21110#}))换句话说,#({:a %})扩展到了类似于(fn [x] ({:a x}))的东西。这个函数正文中的问题是,映射是作为一个函数调用的,没有参数。
地图的行为就像函数:它们是键的函数。但他们希望至少有一个论点,最多两个论点:
({:a 1} :a) ;;=> :a
({:a 1} :b 2) ;;=> 2您根本不打算将地图作为函数调用。你只是想要地图。匿名函数文字总是扩展为函数调用,不能产生直接值。您可以通过以下几种方法解决这个问题:
#(-> {:a %})#(identity {:a %})#(hash-map :a %)#(do {:a %})(fn [x] {:a x})我更喜欢后者,虽然我觉得第一个很有趣。就像在说:我想还我指的东西。
https://stackoverflow.com/questions/39937296
复制相似问题