2016-05-25 2 views
8
user=> (rseq [:a :b]) 
(:b :a) 
user=> (rseq (rseq [:a :b])) 
ClassCastException clojure.lang.APersistentVector$RSeq cannot be cast to 
    clojure.lang.Reversible clojure.core/rseq (core.clj:1532) 

Почему rseq не принимает результаты по предыдущим звонкам до rseq?Почему вы не можете использовать RSeq?

Я прочитал в докштрине, что аргумент должен быть (фактически, «может быть») вектором или отсортированной картой, а приведенное выше показывает, что оно не может быть RSeq, поэтому я уже это знаю. Я хочу знать: есть ли веские основания для этого ограничения? Это просто надзор, или это ограничение дает некоторую важную выгоду?

Кроме того, есть ли удобный способ для этого, кроме как никогда не звонить rseq? Трудно узнать, когда вы возвращаете RSeq из одной функции, может ли какая-то другая функция в другом месте называть rseq.

Я прошу, потому что это разочаровывает, когда мои ошибки исключают код для такой неожиданной причины. s. Если бы я знал, почему это имеет смысл, я мог бы с меньшей вероятностью совершить подобные и подобные ошибки.

ответ

4

Вы не можете позвонить по номеру rseq на seq, так как вам нужна входная коллекция с постоянным временным произвольным доступом к полнофункциональным характеристикам fullfill rseq, а seqs обеспечивают эффективный доступ (итерацию) от головы вниз.

Вызов rseq на результат rseq не может быть обложен специальным обложкой, чтобы вернуть оригинальную коллекцию, поскольку оригинальная коллекция никогда не является секвой. И если вызов rseq на RSeq вернет что-то (seq coll), это не упростит поддержку (rseq (drop x (rseq coll))). Вероятно, это были такие осложнения, которые препятствовали тому, чтобы разработчики языка поддерживали «рекурсивный» rseq.

Если вам нужна общая функция разворота, используйте reverse - это будет медленнее. Если вы можете, вы, вероятно, просто хотите сохранить ссылку на (seq coll) и (rseq coll), если вам нужны оба.

+0

Спасибо! Я думал, что «RSeq» (объект, возвращаемый 'rseq') может быть легко изменен в течение постоянного времени, просто разворачивая' RSeq', но я думаю, что вы прибили его: вектор не является seq. Я все еще новичок в Clojure, и я все еще часто неправильно читаю «возвращает seq», поскольку «возвращает что-то последовательное, как вектор», а не «возвращает что-то вроде итератора». –

+0

Еще одна мысль: не удалось ли 'RSeq' быть реверсивным в постоянное время, возвращая seq на исходный вектор или отсортированную карту? –

+2

Да, это может быть сделано для работы, но только для оригинального RSeq. Вы не можете легко поддерживать (например, rseq (drop 1 (rseq coll)). –

3

Поскольку rseq работает только для специальных обратимых последовательностей. Но результатом его применения является обычная последовательность. Вы всегда можете проверить, если вы можете rseq последовательность с reversible? предиката:

(defn reverse* [s] 
    (if (reversible? s) 
    (rseq s) 
    (reverse s))) 

Почему это запасной вариант не в rseq (или reverse) сама функция? Причина в том, что rseq должен гарантировать предсказуемость времени выполнения, я думаю.

Если вам действительно нужно обратить коллекции позже, вы бы лучше держать его в качестве вектора, например: (rseq (vec (rseq [1 2 3])))

+0

Итак, это обычная практика или, по крайней мере, разумная практика, только вызывать 'rseq', чтобы сделать то, что вы собираетесь использовать в коде, который вы знаете полностью? Мне интересно, следует ли мне думать о «rseq» как о «опасной» функции, как в «Ну, когда вы вызывали« rseq », вы практически просили исключение во время выполнения». –

+0

хорошо, если вы посмотрите на него с точки зрения «протокола» (некоторый набор функций может применяться только к некоторым типам коллекций), все становится чистым, например: 'assoc' или' update' можно вызывать только с помощью «Ассоциативного» ',' rseq' можно было вызвать только с помощью 'Reversible' и т. д. Поэтому да, вы должны помнить об этом в своем коде и дважды проверять типы значений, возвращаемые внешними библиотеками. – leetwinski

+2

Чтобы ответить на ваш вопрос о обычной практике, за последние шесть лет, работая с Clojure в качестве моей дневной работы, я не видел никаких звонков в rseq. –