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

欢迎!请参阅关于页面以了解更多关于这个网站的信息。

+11
集合
已关闭

reduce-kv 需要将元素索引传递给"key"参数时,在向量上按预期工作。然而,它在 subvec 上失败,因为 clojure.lang.APersistentVector$SubVector 没有实现 IKVReduce。

(reduce-kv + 0 (link: 1 2 3))
9

(reduce-kv + 0 (subvec (link: 1 2 3) 1))
IllegalArgumentException 没有为类: clojure.lang.APersistentVector$SubVector 的协议: #'clojure.core.protocols/IKVReduce 找到方法: :kv-reduce clojure.core/-cache-protocol-fn (core_deftype.clj:583)

一个解决办法是将 subvec 复制到一个向量中

(reduce-kv + 0 (into (link: ) (subvec (link: 1 2 3) 1)))
6

但请注意,vec 不会在这里工作。从 Clojure 1.7 开始,vec 将返回一个 subvec 而不是复制。

(reduce-kv + 0 (vec (subvec (link: 1 2 3) 1)))
IllegalArgumentException 没有为类: clojure.lang.APersistentVector$SubVector 的协议: #'clojure.core.protocols/IKVReduce 找到方法: :kv-reduce clojure.core/-cache-protocol-fn (core_deftype.clj:583)

Clojure 用户期望子向量支持所有正常的向量操作,而这个异常让人困惑。问题的原因是 subvec 返回一个不实现 clojure.lang.IKVReduce 的 clojure.lang.APersistentVector$SubVector。PersistentVector 继承自 APersistentVector 并实现了 IKVReduce,但 SubVector 没有获得任何 IKVReduce 支持这似乎只是一个疏忽。

附上两个补丁。第一个补丁通过在 core.clj 中扩展 IKVReduce 协议来解决问题,这对于 Clojure 用户来说是一个方便的解决方案。第二个补丁(由 Alex Miller 建议),直接将 IKVReduce 接口的 Java 实现添加到 APersistentVector$SubVector。应该审查第二个补丁。同样的测试包含在两个补丁中。

已关闭,标记为:已修复在 1.11.0-alpha3

10 个答案

0

评论人:[email protected]

以下是我的当前解决方案

`
(extend-type clojure.lang.APersistentVector$SubVector
clojure.core.protocols/IKVReduce
(kv-reduce [subv f init]

(transduce (map-indexed vector)
           (fn ([ret] ret) ([ret [k v]] (f ret k v)))
           init
           subv)))

`

在我的测试中,通常将子向量复制到常规向量中会更快,但我喜欢transduce修复的外观。如果在APersistentVector.java中添加原生Java实现可能更快。如果Clojure/core团队想要补丁,我将愿意做这项工作。

0
_评论人:[email protected]_

使用更多互操作性改进性能的解决方案。与正常向量reduce-kv的速度相当。


(when-not (satisfies?   clojure.core.protocols/IKVReduce (subvec [1] 0))
  (extend-type clojure.lang.APersistentVector$SubVector
    clojure.core.protocols/IKVReduce
    (kv-reduce
      [subv f init]
      (let [cnt (.count subv)]
        (loop [k 0 ret init]
          (if (< k cnt)
            (let [val (.nth subv k)
                ret (f ret k val)]
              (if (reduced? ret)
                @ret
                (recur (inc k) ret)))
            ret))))))
0

评论人:[email protected]

支持SubVector的IKVReduce

0

评论人:[email protected]

补丁还为常规向量和子向量上的reduce-kv添加了测试。

0

评论人:alexmiller

为什么不在APersistentVector$SubVector中直接实现IKVReduce呢?

0

评论人:[email protected]

Java对SubVector上IKVReduce的实现

0

评论人:[email protected]

是的,这样是有道理的。我犹豫了一下,因为我不想重新修改层次结构,让SubVector成为PersistentVector的子类,但这并不是修复这个错误所必需的。CLJ-2065-Support-IKVReduce-on-SubVector.patch只是Java端,加上同一测试。

0

评论人:[email protected]

更新补丁以内联nth()调用,避免不必要的边界检查。

0
0

JIRA问题单有些过时了。它只说这个问题影响到1.9,但我可以确认它仍然存在于1.10.3中。

是的,通常我们假设这只是“在哪注意到”的,除非由于回归或其他原因有进一步的详细说明,所以没有什么大不了的。
...