为什么你不能rseq一个RSeq?

时间:2016-05-25 08:10:34

标签: clojure sequence reverse rationale

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的结果?

我在docstring中读到参数必须是(实际上,“可以是”)一个向量或有序映射,而上面显示它不能是RSeq,所以我已经知道了那。我想知道的是:有这个限制的充分理由吗?这只是一种疏忽,还是这种限制提供了一些重要的好处?

此外,除了从不调用rseq之外,还有一个方便的解决方法吗?很难知道,当你从一个函数返回RSeq时,其他某个函数是否可以在其上调用rseq

我在问,因为看到我的代码因为这种令人惊讶的原因s而抛出异常令人沮丧。如果我知道为什么这有意义,我可能不太可能犯这种和类似的错误。

2 个答案:

答案 0 :(得分:4)

你不能在seq上调用rseq,因为你需要一个输入集合,可以随机访问fullfill rseq的常量性能特性,而seqs只提供有效的访问(迭代)从头朝下。

rseq的结果调用rseq不能特殊地返回原始集合,因为原始集合永远不是seq。如果在RSeq上调用rseq会返回(seq coll)的内容,则不会直接支持(rseq (drop x (rseq coll)))。可能是那些使语言实现者无法支持“递归”rseq的并发症。

如果您需要一般的反转功能,请使用reverse - 这将更慢。如果可以,您可能只想保留对(seq coll)(rseq coll)的引用,如果您需要的话。

答案 1 :(得分:3)

因为rseq仅适用于特殊的可逆序列。但其应用的结果是普通的seq。您始终可以检查rseq带有reversible?谓词的序列:

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

为什么这个后备不在rseq(或reverse)函数本身?原因是我认为rseq应该保证其执行时间的可预测性。

如果您确实需要稍后撤回收藏,最好将其保存为矢量,例如:(rseq (vec (rseq [1 2 3])))