Clojure 惰性序列使用 [英] Clojure lazy sequence usage

查看:32
本文介绍了Clojure 惰性序列使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法理解如何在 Clojure 中创建惰性序列.

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:

用法:(lazy-seq & body)获取返回 ISeq 或 nil 的表达式主体,并产生一个 Seqable 对象,它只会在第一次 seq 时调用主体被调用,并将缓存结果并在所有后续序列调用.

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

所以,我不明白的第一件事是,由于lazy-seq 在对conj 的调用之外,它如何防止conj 在求值时生成无限序列?

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?

推荐答案

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

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)

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

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 只是创建惰性序列的众多可能方法之一,它通常不是最方便的.以下是创建惰性序列的其他一些有趣/有用的方法:

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)

这篇关于Clojure 惰性序列使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆