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

vik*_*ata 7 evaluation f# eager seq

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

> seq { for i in 1 .. 10 do yield i * i };;
val it : seq<int> = seq [1; 4; 9; 16; ...]
Run Code Online (Sandbox Code Playgroud)

非常感谢.

Mar*_*ann 19

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

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

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

问题是当你评估这两个表达式时,没有任何反应:

> 

val lazySeq : seq<int>
val nothingHappens : seq<unit>
Run Code Online (Sandbox Code Playgroud)

因为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]
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

  • 在我的情况下,序列是从需要在构建后处理的资源构建的。除了调用 toList 然后 toSeq,然后处理资源并返回结果序列之外,我没有看到任何其他方法。即使没有副作用,在这种情况下也需要强制评估。 (2认同)

Car*_*ten 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|]
Run Code Online (Sandbox Code Playgroud)