首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Clojure中使用map和匿名函数的异常

在Clojure中使用map和匿名函数的异常
EN

Stack Overflow用户
提问于 2016-10-08 20:57:51
回答 1查看 510关注 0票数 1

我在玩Clojure地图,我发现了一个我无法理解的情况。

假设我有张这样的地图:

代码语言:javascript
复制
(def map-test {:name "head" :size 3})

我想改变这个映射的值,在Clojure中,通常的方法是用修改过的数据生成一个新的映射。

所以我有这样的功能:

代码语言:javascript
复制
(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" ...}等等:

代码语言:javascript
复制
(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时,调试器将抛出此异常。

下面是堆栈跟踪的最后一部分:

代码语言:javascript
复制
   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
....

但是,如果我使用一个与匿名函数相同的非匿名函数:

代码语言:javascript
复制
(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)可以工作。为什么?我错过了什么?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-10-08 21:12:03

该错误类似于这个简化的示例:

代码语言:javascript
复制
(map #({:a %}) [1 2 3])

clojure.lang.ArityException: Wrong number of args (0) passed to: PersistentArrayMap

您可以展开#({:a %}),查看实际正在编译和执行的代码:

代码语言:javascript
复制
(macroexpand '#({:a %}))
;;=> (fn* [p1__21110#] ({:a p1__21110#}))

换句话说,#({:a %})扩展到了类似于(fn [x] ({:a x}))的东西。这个函数正文中的问题是,映射是作为一个函数调用的,没有参数。

地图的行为就像函数:它们是键的函数。但他们希望至少有一个论点,最多两个论点:

代码语言:javascript
复制
({:a 1} :a) ;;=> :a
({:a 1} :b 2) ;;=> 2

您根本不打算将地图作为函数调用。你只是想要地图。匿名函数文字总是扩展为函数调用,不能产生直接值。您可以通过以下几种方法解决这个问题:

  • #(-> {:a %})
  • #(identity {:a %})
  • #(hash-map :a %)
  • #(do {:a %})
  • (fn [x] {:a x})

我更喜欢后者,虽然我觉得第一个很有趣。就像在说:我想还我指的东西。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39937296

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档