Почему ASeq требует коллекцию для реализации Sequential для обеспечения эквивалентности? - PullRequest
0 голосов
/ 10 декабря 2018

Я пишу свой собственный 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 обрабатывает эквивалентность, я проверил его источник.Он делегирует ASeq, и метод ASeq equiv начинается со строк:

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

Поскольку мой диапазон не реализует Sequential или List, эта проверка завершается неудачно.Он даже не пытается перебрать мой диапазон для сравнения значений.

В чем здесь причина?Sequential это просто пустой интерфейс.Кажется, он просто существует, чтобы «помечать» классы как последовательные, не требуя каких-либо методов.

Я мог бы просто реализовать свой диапазон Sequential, чтобы разрешить проверку, но мне интересно, должна ли моя функция эквивалентности включатьтакая же проверка, как и ASeq.Это кажется ненужной проверкой, так как seq уже потерпит неудачу при неверном аргументе через clojure.lang.RT/seqFrom.

Какова цель проверки Sequential, если я должен реализовать Sequential, чтобы успокоить такоеметоды, и я должен сделать такую ​​проверку в аналогичных методах?

1 Ответ

0 голосов
/ 10 декабря 2018

Какое возвращаемое значение вы хотели бы получить от

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

или от

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

?В обоих случаях две коллекции неразличимы после их seq (в любом случае, в зависимости от того, как хешируется #{1 2}).Но они явно не являются равными коллекциями: карты и наборы ведут себя совершенно иначе, чем списки и векторы.Главное, что отличает каждую пару, это то, что одна из них является последовательной (предназначена для последовательного использования), а другая - нет.Это то, для чего предназначен этот интерфейс тегов.

Итак, да, вы должны проверить Sequential, прежде чем объявлять ваш последовательный объект равным некоторому другому объекту: он не может быть разумно равным чему-либо непоследовательному.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...