11

我看到一些示例表明我们可以在 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.

有什么办法可以解决这个问题,还是我在某处做出了不正确的假设?

4

2 回答 2

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

xs仍然是一个惰性序列,因此您可以毫无问题地使用解构。不过,这将强制 的第一个元素xs。(解构使用向量表示法,但不一定在幕后使用向量。)

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

于 2013-05-24T01:28:32.740 回答
5

绑定向量[x & xs]实际上并不是在运行时构造向量。这只是用于解构为头尾的符号。

所以它适用于无限序列:

(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
于 2013-05-24T02:23:29.760 回答