如何在Clojure中将惰性序列转换为非惰性序列

Tim*_*ons 91 clojure lazy-evaluation

我在Clojure中尝试了以下内容,期望返回一个非惰性序列的类:

(.getClass (doall (take 3 (repeatedly rand))))
Run Code Online (Sandbox Code Playgroud)

但是,这仍然会回归clojure.lang.LazySeq.我的猜测是doall评估整个序列,但返回原始序列,因为它仍然可用于记忆.

那么从懒惰中创建一个非懒惰序列的惯用手段是什么?

小智 151

你需要的就是doall.仅仅因为seq具有类型LazySeq并不意味着它具有待定的评估.懒惰的seqs缓存它们的结果,所以你需要做的就是走懒惰的seq一次(就像doall一样)以强制它全部,从而使它变得非懒惰.序列并没有强制整个集合进行评估.

  • 我相信你只是称之为"已实现?". (10认同)
  • 我已将此更改为已接受的答案.在相关的说明中,您可以通过什么方式确定LazySeq之前是否已经过评估? (2认同)
  • 可能应该有一个“realize”操作来匹配“realized?”。 (2认同)
  • 这一切都非常好。但是,由于像“包含?”这样的函数并不关心您是否意识到了惰性序列,因此这回答了所提出的特定问题,但对问题标题的回答较少。 (2认同)

Art*_*ldt 66

这在某种程度上是分类学的问题.懒惰序列只是一种类型的序列,如列表,向量或映射.所以答案当然是"这取决于你想得到什么类型的非懒惰序列:
从你的选择:

  • 一个ex-lazy(完全评估)的懒惰序列 (doall ... )
  • 顺序访问列表 (apply list (my-lazy-seq)) OR (into () ...)
  • 用于以后随机访问的向量 (vec (my-lazy-seq))
  • 如果你有特殊目的,可以使用地图或集合.

您可以拥有您需要的大多数套房的任何类型的序列.

  • 接受的答案在技术上是正确的,但这个答案对我来说最有用.我试图将一个函数映射到一个向量,然后将结果吐出到一个文件,甚至在调用doall之后,该文件包含"clojure.lang.LazySeq@address"而不是序列的内容.在值图上调用vec返回了我需要吐出的文件. (4认同)
  • @JesseRosalia 很高兴知道所有 SO 中唯一的 Rich Hickey 回应在技术上是正确的。;-) (2认同)

Pet*_*ter 21

这个有钱人似乎知道他的咒语,是绝对正确的.
但是我认为这个代码片段,使用你的例子,可能是这个问题的有用补充:

=> (realized? (take 3 (repeatedly rand))) 
false
=> (realized? (doall (take 3 (repeatedly rand)))) 
true
Run Code Online (Sandbox Code Playgroud)

确实类型没有改变,但实现已经

  • 这个有钱人:D哈哈 (20认同)
  • @nimrod :)然而,双关语意味着"hísclojure". (9认同)
  • 对于那些不知道的人,"富人"发明了Clojure. (9认同)
  • 但值得注意的是,你不需要强制整个序列为`realize?`返回`true`.例如`(让[r(范围)r?(实现?r)](doall(取1 r))[r?(实现?r)])=> [false true]` (2认同)

lee*_*eor 7

我偶然发现这篇关于不是递归的博客文章doall.为此,我发现帖子中的第一条评论就是诀窍.有点像:

(use 'closure.walk)
(postwalk identity nested-lazy-thing)
Run Code Online (Sandbox Code Playgroud)

我发现这在单元测试中非常有用,我想强制评估一些嵌套应用程序map来强制错误条件.


小智 5

(.getClass (into '() (take 3 (repeatedly rand))))
Run Code Online (Sandbox Code Playgroud)

  • 这是一个糟糕的主意.它反转输入seq. (3认同)
  • 当然,在这种情况下,反转输入没有区别,因为它们只是3个随机数.... :-) (3认同)