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

欢迎!请查看 关于 页面以获取更多关于如何使用本网站的信息。

+11
集合
闭合

reduce-kv 在将元素索引作为“键”参数传递给向量时按预期工作。但是,在 subvec 上失败,因为 clojure.lang.APersistentVector$SubVector 没有实现 IKVReduce。

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

(reduce-kv + 0 (subvec (link: 1 2 3) 1))
IllegalArgumentException 没有实现方法::kv-reduce 的协议:#'clojure.core.protocols/IKVReduce 错误,类:clojure.lang.APersistentVector$SubVector 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 没有实现方法::kv-reduce 的协议:#'clojure.core.protocols/IKVReduce 错误,类:clojure.lang.APersistentVector$SubVector clojure.core/-cache-protocol-fn (core_deftype.clj:583)

Clojure 用户期望子向量支持所有正常向量操作,而这个异常很令人困惑。问题的原因是在 clojure.lang.APersistentVector$SubVector 中没有实现 clojure.lang.IKVReduce。PersistentVector 从 APersistentVector 继承并实现了 IKVReduce,但是 SubVector 没有获得 IKVReduce 的支持。这可能是疏忽。

附带了两个补丁。第一个通过在 core.clj 中扩展 IKVReduce 协议修复了问题。这对 Clojure 用户来说很方便,可以将其作为解决方案添加到代码中。第二个补丁,如 Alex Miller 建议,在 APersistentVector$SubVector 中直接添加了 IKVReduce 接口的 Java 实现。应该审查第二个补丁。两个补丁中都包含了相同的测试。

备注:已固定在 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的子类,但实际上这并不是修复bug的必要条件。CLJ-2065-Support-IKVReduce-on-SubVector.patch仅是Java方面的代码,还包括相同的测试。

0

评论者:[email protected]

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

0
0

JIRA工单有点过时。它只说该bug会影响1.9,但我可以确认它仍然存在于1.10.3中。

是的,我们通常假设这只是“及时发现”的问题,除非由于回归或其他原因需要进行进一步说明,所以这不是大问题。
...