F#:如何评估“seq”以急切获取其所有值?

时间:2016-02-03 05:37:29

标签: f# evaluation seq eager

我们知道在F#中,seq是惰性评估的。我的问题是,如果我有一个数量有限的seq,如何将它转换为包含其所有值的一些数据类型?

> seq { for i in 1 .. 10 do yield i * i };;
val it : seq<int> = seq [1; 4; 9; 16; ...]

非常感谢。

2 个答案:

答案 0 :(得分:17)

来自@Carsten的答案是正确的:如果您希望将延迟评估的序列转换为列表或数组,则可以使用Seq.toArraySeq.toList。但是,不要使用这些功能强制进行评估。

人们倾向于问这个问题的最常见原因是因为他们有一个涉及副作用的预测,他们想要强制进行评估。举个例子,希望将值打印到控制台:

let lazySeq = seq { for i in 1 .. 10 do yield i * i }
let nothingHappens = lazySeq |> Seq.map (printfn "%i")

问题在于,当您评估这两个表达式时,没有任何反复发生

> 

val lazySeq : seq<int>
val nothingHappens : seq<unit>

由于nothingHappens是一个延迟评估的序列,因此map不会产生任何副作用。

人们经常诉诸Seq.toListSeq.toArray以强制进行评估:

> nothingHappens |> Seq.toList;;
1
4
9
16
25
36
49
64
81
100
val it : unit list =
  [null; null; null; null; null; null; null; null; null; null]

虽然这有效,但并不是特别惯用;它会产生一种奇怪的返回类型:unit list

更惯用的解决方案是使用Seq.iter

> lazySeq |> Seq.iter (printfn "%i");;
1
4
9
16
25
36
49
64
81
100
val it : unit = ()

正如您所看到的,这会强制进行评估,但具有更合理的返回类型unit

答案 1 :(得分:8)

使用Seq.toArray(对于数组)或Seq.toList(对于列表);)

还有更多 - 只需选择;)

例如:

> seq { for i in 1 .. 10 do yield i * i } |> Seq.toArray;;
val it : int [] = [|1; 4; 9; 16; 25; 36; 49; 64; 81; 100|]