2024 Clojure 状态调查! 分享您的想法。

欢迎!请参阅 关于 页面以获取更多有关此工作方式的信息。

0
Clojure
我在一个递归函数折叠中遇到了一个让人困惑的异常。以下是 REPL 转录:


nREPL 服务器在端口 57818 上启动于主机 127.0.0.1 - 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 函数名)
            ;(find-doc "部分名称")
  源:(source 函数名)
 Javadoc:(javadoc java对象或类)
    退出: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

因为我发现了这个不一致性(我不确定这是一个错误),所以我花了很长时间才解决这个问题。


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=>


(我已在定义中放置了测试输入,但使用定义的变量始终失败,但常量总是成功!)

2 条答案

0

评论作者: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}}参数而不是调用它。另一个修复方案可能将PHM的{{.fold}}更改为创建更符合Clojure函数样式的对象(可调用和可被调用)。

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