是否有可能在clojure中对懒惰序列进行破坏的头/尾分离?

时间:2013-05-24 01:18:40

标签: clojure

我看到一些例子表明我们可以在clojure中得到一个很好的头/尾解构,如下所示:

(if-let [[x & xs] (seq coll)]

但是我认为这对延迟序列不起作用,因为这会将值放入一个不是惰性的向量中。我尝试将矢量形式更改为列表形式,它给了我绑定错误,引用与否。

如果没有这样的绑定,似乎如果我有一个懒惰的序列,其中每个元素是前一个元素的计算密集型方程式,我必须做两次计算才能得到头部和尾部单独的陈述,对吗?

(let [head (first my-lazy-seq) ;; has to calculate the value of head.
      tail (rest my-lazy-seq)] ;; also has to calculate the value of head to prepare the rest of the sequence.

有没有办法解决这个问题,或者我在某个地方做出了错误的假设?

2 个答案:

答案 0 :(得分:9)

user=> (let [[x & xs] (range)] [x (take 10 xs)])
[0 (1 2 3 4 5 6 7 8 9 10)]

xs仍然是一个懒惰的seq,所以你可以毫无问题地使用解构。但这会强制xs的第一个元素。 (解构使用矢量符号,但它不一定使用封面下的矢量。)

关于你的第二个问题:lazy seqs缓存他们的结果,所以你的第二个选项也可以在没有额外重新计算的情况下工作。头部只计算一次。

答案 1 :(得分:4)

绑定向量[x & xs]实际上并不是在运行时构造向量。它只是用于解构为head& amp;尾。

所以它在无限序列上工作正常:

(if-let [[x & xs] (range)]
  (apply str x (take 9 xs)))
=> "0123456789"

在这种情况下,解构形式实际上会生成一个惰性序列,您可以按如下方式观察:

(if-let [[x & xs :as my-seq] (range)]
  (class my-seq))
=> clojure.lang.LazySeq