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

欢迎!请查看关于页面了解更多关于这个平台的信息。

+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 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)

Clojure用户期望子向量支持所有正常的向量操作,而这个异常让人困惑。问题产生的原因是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)))

`

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

在SubVector上实现IKVReduce的Java版本

0

评论者:[email protected]

是的,这很有道理。我犹豫了一会,因为我不想重新设计层次结构使SubVector成为PersistentVector的子类,但这并不是修复这个错误所必需的。"CLJ-2065-Support-IKVReduce-on-SubVector.patch"只是Java方面的修改,还有一个相同的测试。

0

评论者:[email protected]

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

0
0

JIRA问题单(https://clojure.atlassian.net/browse/CLJ-2065)有点过时了。它只说该错误影响1.9,但我可以确认它仍然存在于1.10.3中。

是的,通常我们默认这是“出现的位置”问题,除非因为回归或其他原因有进一步的说明,所以没事。
...