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

Car*_*ate 5 clojure

我正在写自己的range实现ISeq.我最初的实现equiv只是调用seq我的范围和另一个列表,并使用=以下方法进行比较:

(defn equals? [this-range other-range]
  (= (seq this-range) (seq other-range)))
Run Code Online (Sandbox Code Playgroud)

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

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

(= (range 5 10)
   (new-range 5 10))
=> false ; Uh oh
Run Code Online (Sandbox Code Playgroud)

new-range我的自定义构造函数在哪里.

为了了解LongRange句柄的等效性,我检查了它的来源.它代表们ASeq,和ASeqequiv方法开始与线:

public boolean equiv(Object obj) {
    if (!(obj instanceof Sequential) && !(obj instanceof List)) {
        return false;
. . .
Run Code Online (Sandbox Code Playgroud)

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

这是什么原因?Sequential只是一个空的界面.似乎只是存在将类"标记"为顺序而不需要任何方法.

我可以让我的范围工具Sequential允许检查,但我想知道我的等效功能是否应该包括相同的检查ASeq.这似乎是一个不必要的检查,因为seq已经失败了一个坏的论点通过clojure.lang.RT/seqFrom.

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

ama*_*loy 1

您希望从中获得什么返回值

(= [1 2] #{1 2})
Run Code Online (Sandbox Code Playgroud)

或来自

(= '([1 2]) {1 2})
Run Code Online (Sandbox Code Playgroud)

?在这两种情况下,这两个集合在你使用seq它们之后是无法区分的(无论如何,这取决于#{1 2}散列的方式)。但它们显然不是相等的集合:映射和集合的行为与列表和向量非常不同。每一对的主要区别在于,其中一个是顺序的(旨在以顺序方式使用),而另一个则不是。这就是这个标签接口的用途。

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