如何在 Clojure 中将惰性序列转换为非惰性序列
-
10-07-2019 - |
题
我在 Clojure 中尝试了以下操作,期望返回非惰性序列的类:
(.getClass (doall (take 3 (repeatedly rand))))
然而,这仍然返回 clojure.lang.LazySeq
. 。我的猜测是 doall
确实评估整个序列,但返回原始序列,因为它对于记忆仍然有用。
那么从惰性序列创建非惰性序列的惯用方法是什么?
解决方案
doall 就是您所需要的。仅仅因为seq具有类型LazySeq并不意味着它具有待定的评估。懒惰的seqs缓存它们的结果,所以你需要做的就是走懒惰的seq一次(就像doall一样)以强制它全部,从而使它变得非懒惰。 seq 不强制要对整个集合进行评估。
其他提示
这在某种程度上是一个分类问题。 惰性序列只是序列的一种类型 就像列表、矢量或地图一样。所以答案当然是“这取决于您想要获得什么类型的非惰性序列:
从以下选项中选择:
- 前惰性(完全评估)惰性序列
(doall ... )
- 用于顺序访问的列表
(apply list (my-lazy-seq)) OR (into () ...)
- 用于稍后随机访问的向量
(vec (my-lazy-seq))
- 如果您有特殊目的,可以准备一张地图或一套。
您可以选择最适合您需求的任何类型的序列。
这个富家似乎知道他的咒语并且绝对正确。
但是我认为这个代码片段,使用你的例子,可能是这个问题的有用补充:
=> (realized? (take 3 (repeatedly rand)))
false
=> (realized? (doall (take 3 (repeatedly rand))))
true
确实类型没有改变,但实现有
我偶然发现了这个博客发布关于doall
不是递归的。为此,我发现帖子中的第一条评论就是诀窍。有点像:
(use 'closure.walk)
(postwalk identity nested-lazy-thing)
我发现这在单元测试中非常有用,我想强制评估map
的一些嵌套应用程序来强制错误条件。
(.getClass (into '() (take 3 (repeatedly rand))))
不隶属于 StackOverflow