【发布时间】:2026-02-05 04:25:01
【问题描述】:
我们知道在 F# 中,seq 是惰性求值的。我的问题是,如果我有一个值数量有限的 seq,如何将其转换为包含其所有评估值的数据类型?
> seq { for i in 1 .. 10 do yield i * i };;
val it : seq<int> = seq [1; 4; 9; 16; ...]
非常感谢。
【问题讨论】:
标签: 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; ...]
非常感谢。
【问题讨论】:
标签: f# evaluation seq eager
@Carsten 的答案是正确的:如果您希望将延迟评估的序列转换为列表或数组,可以使用Seq.toArray 或Seq.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.toList或Seq.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。
【讨论】:
使用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|]
【讨论】: