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

Dax*_*ohl 8 clojure

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

(if-let [[x & xs] (seq coll)]
Run Code Online (Sandbox Code Playgroud)

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

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

(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.
Run Code Online (Sandbox Code Playgroud)

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

man*_*nge 9

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

xs仍然是一个懒惰的seq,所以你可以使用解构没有问题.不过,这将迫使第一个元素xs.(解构使用矢量符号,但它不一定使用封面下的矢量.)

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


mik*_*era 5

绑定向量[x & xs]实际上并不是在运行时构建向量。它只是用于解构为 head & tail 的符号。

所以它适用于无限序列:

(if-let [[x & xs] (range)]
  (apply str x (take 9 xs)))
=> "0123456789"
Run Code Online (Sandbox Code Playgroud)

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

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