2024 Clojure状况调研!上分享您的想法。

欢迎!请查看关于页面了解更多信息。

+11
集合
已关闭

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

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

(reduce-kv + 0 (subvec (link: 1 2 3) 1))
IllegalArgumentException No implementation of method: :kv-reduce of protocol: #'clojure.core.protocols/IKVReduce found for class: clojure.lang.APersistentVector$SubVector clojure.core/-cache-protocol-fn (core_deftype.clj:583)

一个解决方案是将子向量和复制到向量中

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

然而,这里的vec不会起作用。从Clojure 1.7开始,vec会返回一个子向量和而不是复制。

(reduce-kv + 0 (vec (subvec (link: 1 2 3) 1)))
IllegalArgumentException No implementation of method: :kv-reduce of protocol: #'clojure.core.protocols/IKVReduce found for class: 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用户提供了一个方便的方案,可以通过将补丁直接添加到代码中作为解决方案。第二个补丁添加了直接到APersistentVector$SubVector的Java实现IKVReduce接口。应审查第二个补丁。两个补丁都包含相同的测试。

关闭时的注解:在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)))

`

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

0
_由 [email protected] 发表的评论_

使用更多 interop 进行修订,以提高性能。与正常向量 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] 发表的评论:

这个补丁还添加了在常规向量和 subvector 上进行 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
参考:[链接](https://clojure.atlassian.net/browse/CLJ-2065)(由 [email protected] 提出)
0

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

是的,通常我们会假设这只是“注意到的地方”而已,除非因为回归或其他原因需要进一步的说明,所以没什么大不了的。
...