如何在Clojure中将延迟序列转换为非延迟


95

我在Clojure中尝试了以下操作,期望返回非延迟序列的类:

(.getClass (doall (take 3 (repeatedly rand))))

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

那么,从懒惰序列创建非懒惰序列的惯用方法是什么?


我很惊讶,没有人问你为什么关心的实际类型的返回值的doall
焦油

您可以将其转换为向量:(vec (take 3 (repeatedly rand)))
Kris

Answers:


161

doall是你所需要的全部。仅仅因为seqhas类型LazySeq并不意味着它具有待处理的评估。Lazy seq缓存它们的结果,因此您需要做的就是seq一次(像doall这样)对Lazy进行遍历,以强制全部执行,从而使其变为非Lazy。seq没有强制整个集合进行评估。


2
我已将其更改为可接受的答案。与此相关的是,您可以通过什么方式确定LazySeq是否曾经被评估过?
Tim Clemons

10
我相信你只是打电话realized?
toofarsideways'2

1
可能应该realize进行匹配操作realized?
Reut Sharabani

这一切都很好。但是,由于某些函数之类的函数contains?并不关心您是否意识到了惰性序列,因此这可以回答所询问的特定问题,而对问题的标题的回答则较少。
matanster,

75

这在某种程度上是分类学的问题。 惰性序列只是列表,向量或图谱的一种类型。因此,答案当然是“这取决于您要获得哪种类型的非延迟序列:
从以下选项中进行选择:

  • 前惰性(经过充分评估)的惰性序列 (doall ... )
  • 顺序访问列表 (apply list (my-lazy-seq)) OR (into () ...)
  • 一个向量,供以后随机访问 (vec (my-lazy-seq))
  • 地图或集合(如果您有特殊目的)。

您可以根据自己的需要选择最适合的序列类型。


这是最好的答案。
费利佩2014年

4
可接受的答案在技术上是正确的,但是此答案对我最有用。我试图在一个向量上映射一个函数,然后将结果吐到一个文件中,甚至在调用doall之后,该文件也包含“ clojure.lang.LazySeq@address”而不是序列的内容。在价值地图上调用vec返回了我需要吐出的文件。
杰西·罗莎莉亚

1
@JesseRosalia很高兴知道,SO中唯一且唯一的Rich Hickey响应在技术上是正确的。;-)
Phil Cooper

(vec (my-lazy-seq))在以下情况下不太好:(vec (json/parse-string "{\"foo\":\"bar\"}")) ;; => [["foo" "bar"]]由于cheshire选择从以下位置 生成延迟(json/parse-string)
序列:

缓解上述问题的方法是使用eager(json/parse-string-strict)
codeasone

22

这个有钱人似乎知道他的伪君子,是绝对正确的。
但是,我认为,使用您的示例,此代码片段可能是此问题的有用补充:

=> (realized? (take 3 (repeatedly rand))) 
false
=> (realized? (doall (take 3 (repeatedly rand)))) 
true

确实类型没有改变,但是实现有了改变


2
不过,值得注意的是,您无需强制整个序列realized?返回true。例如(let [r (range) r? (realized? r)] (doall (take 1 r)) [r? (realized? r)]) => [false true]
Alex Coventry

22
这个有钱的人:D哈哈
Nimrod 2014年

10
@nimrod :)然而,双关语本来是在“他的clojure”中。
彼得

10
对于那些不认识的人,“有钱人”发明了Clojure。
erturne 2014年

1
@AlexCoventry您的示例返回[true true]

7

我偶然发现了此博客文章中关于doall不递归的内容。为此,我发现帖子中的第一条评论起到了作用。类似于以下内容:

(use 'closure.walk)
(postwalk identity nested-lazy-thing)

我发现这在单元测试中非常有用,在该单元测试中,我想强制评估某些嵌套应用程序map以强制出错。


5
(.getClass (into '() (take 3 (repeatedly rand))))

3
这是一个可怕的主意。反转输入序列。
合金2011年

3
当然,在这种情况下,反转输入没有什么区别,因为它们只是3个随机数.... :-)
mikera 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.