为什么ASeq要求集合实现Sequential才能允许等效?

时间:2018-12-10 01:07:34

标签: clojure

我正在编写自己的实现range的{​​{1}}。我对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如何处理等效项,我检查了其来源。它委托给LongRangeASeq的{​​{1}}方法以下列行开头:

ASeq

由于我的范围未实现equivpublic boolean equiv(Object obj) { if (!(obj instanceof Sequential) && !(obj instanceof List)) { return false; . . . ,因此此检查失败。它甚至不尝试迭代我的范围以进行值比较。

这是什么原因? Sequential只是一个空接口。似乎只存在“标记”类为顺序类而不需要任何方法。

我可以让我的范围实现List允许检查,但是我想知道我的等效函数是否也应该包括与Sequential相同的检查。不过,这似乎是不必要的检查,因为Sequential在通过ASeq处理错误的参数时已经失败。

进行seq检查的目的是什么,我应该实施clojure.lang.RT/seqFrom来安抚此类方法吗?在类似的方法中也应该进行此类检查吗?

1 个答案:

答案 0 :(得分:1)

您想从中获得什么返回值

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

或来自

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

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

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