F# 无法枚举使用 GetEnumerator 时由 yield 生成的序列

F# Cannot enumerate sequence generated by yield when using GetEnumerator

以下示例基于 snippet 生成的函数,这些函数允许一一枚举序列值。

此处printAreEqual ()给出trueprint2 ()给出12345678910,但print1 ()给出0000000000.

为什么函数 return 不能枚举 return 使用 yield 生成的序列的值?


open System.Linq

let enumerate (xs: seq<_>)  = 
    use en = xs.GetEnumerator()
    fun () ->
        en.MoveNext() |> ignore
        en.Current

let s1 = seq { for i in 1 .. 10 do yield i }
let s2 = seq { 1 .. 10 }

let f1 = s1 |> enumerate
let f2 = s2 |> enumerate

let printAreEqual () = Enumerable.SequenceEqual (s1, s2) |> printf "%b" // true
let print1 () = for i in 1 .. 10 do f1() |> printf "%i" // 0000000000
let print2 () = for i in 1 .. 10 do f2() |> printf "%i" // 12345678910

enumerate 函数中的 use en = ... 有效地执行此操作:

let enumerate (xs: seq<_>) = 
    let en = xs.GetEnumerator()
    let f =
        fun () ->
            en.MoveNext() |> ignore
            en.Current
    en.Dispose()
    f

您总是在开始使用枚举器之前对其进行处理,因此在这种情况下行为可能是未定义的,并且对于具有不同实现的两个序列得到不同结果的原因并不重要。

序列枚举的细粒度控制总是很棘手,并且由于可变状态很难制作辅助函数。