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]

这是我的当前解决方案

`
(扩展类型 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
by
_由:[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
by

评论者:[email protected]

支持IKVReduce功能在SubVector

0
by

评论者:[email protected]

补丁还添加了对常规向量和子向量的reduce-kv测试。

0
by

由:alexmiller发表的评论

为什么不直接在APersistentVector$SubVector中实现IKVReduce?

0
by

评论者:[email protected]

Java在SubVector上实现IKVReduce

0
by

评论者:[email protected]

是的,这合乎逻辑。我犹豫了一下,因为我不想重建层次结构,让 SubVector 成为 PersistentVector 的子类,但这并不是修复该错误所需的。CLJ-2065-Support-IKVReduce-on-SubVector.patch 仅是 Java 一侧,还有相同的测试。

0
by

评论者:[email protected]

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

0
by
0
by

JIRA 问题是有点过时。它说这个错误影响 1.9 版本,但我可以确认它仍然存在于 1.10.3 中。

by
是的,一般情况下我们假设这只是“在哪里注意到的”,除非由于回归或其他原因需要进一步说明,所以没有大问题。
...