Clojure延迟序列用法 [英] Clojure lazy sequence usage

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

问题描述

我无法理解如何在Clojure中创建一个延迟序列。



宏的文档对我来说不清楚:


用法:(lazy-seq& body)
获取返回一个ISeq或nil的表达式体,得到
a只有第一次调用seq
时调用主体的Seqable对象将被调用,并将缓存结果并将其返回所有后续的
seq调用。


我看到的所有示例都像下面这样:

 ;返回从idx开始的序列中的一切n 
(defn myseq-after-n [n]
(...)


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


所以,我没有得到的第一件事是,因为lazy-seq是在conj的调用之外,它如何防止conj在评估时产生无限序列?



我的第二个问题是,延迟序列定义总是采用这种一般形式?

解决方案

p> A lazy-seq调用只是在第一次访问时执行主体,然后在将来再次调用时缓存并返回相同的结果。



如果你想使用它来构建长(或甚至无限)序列,那么你需要递归嵌套在返回的序列中的其他延迟seq调用。这里是关于我能想到的最简单的情况:

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

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

从n开始的序列,后面是(ints-from(inc n))的惰性序列。这是一个无限列表,但这不是一个问题,因为lazy-seq确保(int-from(inc n))只有在需要时被调用。你可以尝试完全相同的代码没有lazy-seq,你会得到一个StackOverflowError非常快。



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

 范围是一种获取无限延迟整数序列的简单方法,从零开始
(获取10(范围))
=> (0 1 2 3 4 5 6 7 8 9)

; map产生延迟序列,所以下面是延迟
(取10(map#(*%%)(range)))
=> (0 1 4 9 16 25 36 49 64 81)

;迭代是一种很好的方法来制作形式为x,f(x),f(f(x))的无限序列.....
(取10(iterate(partial * 2)1))
=> (1 2 4 8 16 32 64 128 256 512)¥b $ b


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?

解决方案

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)

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

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