首页 文章

为什么ASeq需要一个集合来实现Sequential以允许等价?

提问于
浏览
5

我正在编写自己的 range ,它实现了 ISeq . 我对 equiv 的原始实现只是在我的范围和另一个列表上调用 seq ,并使用 = 进行比较:

(defn equals? [this-range other-range]
  (= (seq this-range) (seq other-range)))

这似乎很好,但后来我遇到了一些奇怪的行为:

(= (new-range 5 10)
   (range 5 10))
=> true

(= (range 5 10)
   (new-range 5 10))
=> false ; Uh oh

new-range 是我的自定义构造函数 .

为了了解 LongRange 如何处理等价,我检查了它的来源 . 它委托给 ASeqASeqequiv 方法以行开头:

public boolean equiv(Object obj) {
    if (!(obj instanceof Sequential) && !(obj instanceof List)) {
        return false;
. . .

由于我的范围未实现 SequentialList ,因此此检查失败 . 它甚至没有尝试迭代我的范围来进行值比较 .

这是什么原因? Sequential 只是一个空接口 . 它似乎只是存在于"mark"类中,而不需要任何方法 .

我可以让我的范围实现 Sequential 以允许检查,但我想知道我的等价函数是否应该包括与 ASeq 相同的检查 . 这似乎是一个不必要的检查,因为 seq 将通过 clojure.lang.RT/seqFrom 在一个错误的参数上失败 .

Sequential 检查的目的是什么,我应该实现 Sequential 来安抚这些方法,我应该在类似的方法中进行这样的检查吗?

1 回答

  • 1

    你希望获得什么样的回报 Value

    (= [1 2] #{1 2})
    

    或来自

    (= '([1 2]) {1 2})
    

    ?在这两种情况下,两个集合在它们之后都是无法区分的(取决于 #{1 2} 如何得到哈希值) . 但它们显然不是相同的集合:映射和集合与列表和向量的行为非常不同 . 区分每一对的主要因素是其中一个是Sequential(打算以顺序方式使用)而另一个不是 . 这就是这个标记界面的用途 .

    所以,是的,你应该在声明顺序对象等于某个其他对象之前检查Sequential:它不能合理地等于任何非顺序对象 .

相关问题