函数式编程-Clojure惰性序列usag

我很难理解一个人如何在Clojure中创建一个惰性序列。

宏的文档对我来说一点都不清晰:

用法:(懒惰和身体) 接受返回ISeq或nil的表达式主体,并产生 一个仅在第一次seq时调用主体的Seqable对象 被调用,并将缓存结果并在所有后续结果中返回 seq调用。

我所看到的所有示例似乎都执行以下操作:

; return everything in the sequence starting at idx n
(defn myseq-after-n [n]
  (...)
)

(def my-lazy-seq
  (lazy-seq (conj [init-value] (myseq-after-n 2)))
)

因此,我不明白的第一件事是,由于lazy-seq不在conj的调用范围内,它如何防止conj在求值时生成无限序列?

我的第二个问题是,惰性序列定义是否总是采用这种通用形式?

1个解决方案
56 votes

lazy-seq调用仅在第一次访问主体时执行一次,然后缓存并在以后再次调用时返回相同的结果。

如果要使用它构建长(甚至无限)序列,则需要将其他lazy-seq调用递归嵌套在返回的序列中。 这是我能想到的最简单的情况:

(defn ints-from [n]
  (cons n (lazy-seq (ints-from (inc n)))))

(take 10 (ints-from 7))
=> (7 8 9 10 11 12 13 14 15 16)

任何(ints-from n)调用都会产生以n开头的序列,然后是(ints-from(inc n))的惰性序列。 这是一个无限列表,但这不是问题,因为lazy-seq确保仅在需要时才调用(int-from(inc n))。 您可以在没有lazy-seq的情况下尝试完全相同的代码,并且很快就会收到StackOverflowError。

lazy-seq只是创建惰性序列的许多可能方法之一,而且通常不是最方便的方法。 以下是创建惰性序列的其他一些有趣/有用的方法:

; range is an easy way to get an infinite lazy sequence of integers, starting with zero     
(take 10 (range))
=> (0 1 2 3 4 5 6 7 8 9)

; map produces lazy sequences, so the following is lazy 
(take 10 (map #(* % %) (range)))
=> (0 1 4 9 16 25 36 49 64 81)

; iterate is a good way of making infinite sequenes of the form x, f(x), f(f(x))..... 
(take 10 (iterate (partial * 2) 1))
=> (1 2 4 8 16 32 64 128 256 512)
mikera answered 2020-08-11T00:56:32Z
translate from https://stackoverflow.com:/questions/4992298/clojure-lazy-sequence-usage