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

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

+11
集合
已关闭

当使用作为“key”参数传递的元素索引在向量上使用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 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)

一种解决办法是将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 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)

用户期望子向量支持所有的正常向量操作,这个异常很令人困惑。问题的原因是因为subvec返回一个clojure.lang.APersistentVector$SubVector,它没有实现clojure.lang.IKVReduce。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)))

`

在我的测试中,通常将subvec复制到常规向量中会更快,但我更喜欢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中。

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