分享您的想法,请在 2024 年 Clojure 状态调查

欢迎!有关如何操作的一些更多信息,请参阅 关于 页面。

0
Clojure
在一个递归折叠函数中,我遇到了一个令人困惑的异常。下面的 REPL 转录。


nREPL 服务器在主机 127.0.0.1 的端口 57818 上启动 - nrepl://127.0.0.1:57818
REPL-y 0.3.5,nREPL 0.2.6
Clojure 1.7.0-alpha5
Java HotSpot(TM) 64 位服务器虚拟机 1.7.0_76-b13
    文档:(doc function-name-here)
                   (find-doc "part-of-name-here")
  源:(source function-name-here)
 Javadoc:(javadoc java-object-or-class-here)
    退出:Control+D 或(exit)或(quit)
 结果:存储在变量 *1,*2,*3 中,异常在 *e 中

user=> (use 'foldtest.core)
nil
user=> (source leafs)
(defn leafs [xs]
  (->> (r/mapcat (fn [k v]
                   (if (map? v)
                     (leafs v)
                     [[k v]])) xs)
       (r/foldcat)))
nil
user=> (leafs (hash-map :a (hash-map :b 1 :c 2)))

ClassCastException clojure.lang.PersistentHashMap$1 无法转换为 clojure.lang.IFn  clojure.core.reducers/fjinvoke (reducers.clj:48)
user=> (pst)
ClassCastException clojure.lang.PersistentHashMap$1 无法转换为 clojure.lang.IFn
    clojure.core.reducers/fjinvoke (reducers.clj:48)
    clojure.lang.PersistentHashMap.fold (PersistentHashMap.java:207)
    clojure.core.reducers/eval1347/fn--1348 (reducers.clj:367)
    clojure.core.reducers/eval1220/fn--1221/G--1211--1232 (reducers.clj:81)
    clojure.core.reducers/folder/reify--1247 (reducers.clj:130)
    clojure.core.reducers/fold (reducers.clj:98)
    clojure.core.reducers/fold (reducers.clj:96)
    clojure.core.reducers/foldcat (reducers.clj:318)
    foldtest.core/leafs (core.clj:5)
    foldtest.core/leafs/fn--1367 (core.clj:7)
    clojure.core.reducers/mapcat/fn--1277/fn--1280 (reducers.clj:185)
    clojure.lang.PersistentHashMap$NodeSeq.kvreduce (PersistentHashMap.java:1127)
nil
user=>


请注意,它 *必须* 是嵌套在哈希图中的哈希图。其他数组与哈希图组合似乎没问题


user=> (leafs (array-map :a (hash-map :b 1 :c 2)))
[[:c 2] [:b 1]]
user=> (leafs (hash-map :a (array-map :b 1 :c 2)))
[[:b 1] [:c 2]]
user=> (leafs (hash-map :a (hash-map :b 1 :c 2)))

ClassCastException clojure.lang.PersistentHashMap$1 无法转换为 clojure.lang.IFn  clojure.core.reducers/fjinvoke (reducers.clj:48)
user=> (leafs (array-map :a (array-map :b 1 :c 2)))
[[:b 1] [:c 2]]
user=>


可能相关:CLJCLR-63

由于这种不一致性(我不确定这是否是 bug),我花了一点时间才发现这个问题


user=> (def a {:a 1})
#'user/a
user=> (type a)
clojure.lang.PersistentHashMap
user=> (let [a {:a 1}] (type a))
clojure.lang.persistentArrayMap
user=> (type {:a 1})
clojure.lang.persistentArrayMap
user=>


(我将测试输入放入了def中,但使用定义的变量总是失败,而字面量总是可以工作!)

2 答案

0
by

评论由:favila 制作

我确认此问题在CLJ 1.8和master(1.9)版本中依然存在,使用的是Java 8。

我能够诊断出问题的原因。问题在于PHMs的{{.fold}}方法为{{Callable}}(而不是一个{{IFn}})创建了一个要由{{fjinvoke}}调用的对象,但是{{fjinvoke}}会像调用一个普通的clojure函数({{IFn .invoke}})一样调用它的参数。这是唯一一个提供给{{fjinvoke}}原生{{Callable}}的Clojure-core可折叠数据结构。通常这个问题不会出现,因为任务不是在运行的任务中调用,但是一个嵌套的折叠是在一个已经运行的任务中执行的,并会到达{{fjinvoke}}中的{{(f)}}行并崩溃。

由于Clojure函数本身也是{{Callable}},所以我修复的办法是使{{fjinvoke}}接收一个{{Callable}}并将参数{{.call}},而不是调用它。另一种修复办法是将PHMs的{{.fold}}修改为创建更像Clojure函数的对象(可调用并可调用)。

0
by
参考: https://clojure.atlassian.net/browse/CLJ-1662(由favila报告)
...