Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
565 views
in Technique[技术] by (71.8m points)

functional programming - Clojure lazy sequence usage

I'm having trouble understanding how one creates a lazy sequence in Clojure.

The documentation for the macro isn't at all clear to me:

Usage: (lazy-seq & body) Takes a body of expressions that returns an ISeq or nil, and yields a Seqable object that will invoke the body only the first time seq is called, and will cache the result and return it on all subsequent seq calls.

All the examples that I've seen, seem to do something like the following:

; 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)))
)

So, the first thing I don't get is, since lazy-seq is outside the call to conj, how does it prevent conj from generating an infinite sequence at evaluation?

My second question is, do lazy sequence definitions always take this general form?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

A lazy-seq call just executes the body once the first time it is accessed, then caches and returns the same result whenever it is called again in the future.

If you want to use this to build long (or even infinite) sequences, then you need to recursively nest other lazy-seq calls in the returned sequence. Here's about the simplest case I can think of:

(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)

Any (ints-from n) call produces a sequence starting with n, followed by a lazy sequence of (ints-from (inc n)). It's an infinite list, but that's not a problem because the lazy-seq ensures that (int-from (inc n)) only gets called when it is needed. You could try exactly the same code without the lazy-seq and you'd get a StackOverflowError very quickly.

lazy-seq is just one of many possible ways to create lazy sequences, and it often isn't the most convenient. The following are some other interesting/useful ways to create lazy sequences:

; 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)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...