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

欢迎!有关如何运作的更多信息,请查看关于页面。

+11 投票
集合
已关闭

reduce-kv在传递元素索引作为"key"参数的向量化工作正常。然而,在子向量化时它会失败,因为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用户来说作为临时解决方案方便地插入到代码中。第二个补丁,由Alex Miller建议,直接将IKVReduce接口的Java实现添加到APPersistentVector$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 实现的 IKVReduce 在 SubVector 上的应用

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 中。

是的,通常我们假设这只是“在哪里注意到的”,除非因为回归或其他原因有进一步的详细阐述,所以这不是什么大问题。
...