【问题标题】:F#: how to evaluate a "seq" to get all its values eagerly?F#:如何评估“seq”以急切地获取其所有值?
【发布时间】: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


    【解决方案1】:

    @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

    【讨论】:

    • 在我的情况下,序列是由构建后需要处理的资源构建的。除了调用 toList 然后 toSeq,然后处理资源并返回结果序列之外,我没有看到任何其他解决方法。在这种情况下需要强制进行评估,即使没有副作用。
    • @Kurren 你的例子很有帮助。谢谢!但是,从技术上讲,您的示例中存在 副作用。副作用发生在一次性资源中。
    • 这终于解决了我自己的类似问题......当然是 Ploeh 提供了有用的答案和清晰的解释。感谢您所做的一切。
    【解决方案2】:

    使用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|]
    

    【讨论】: