我看到一些例子表明我们可以在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.
有没有办法解决这个问题,或者我在某个地方做出了错误的假设?
答案 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