Seq.iter 无法迭代使用 seq.collect 和序列表达式创建的序列

Igo*_*hov 2 f#

我在 F# 代码中遇到了一个错误,我已将其简化为以下最小再现序列,但现在我不明白为什么它会这样工作。

let duplicate element =
    [ element; element ]

let passThrough (sq: seq<_>) =
    use it = sq.GetEnumerator ()
    seq {
        while (it.MoveNext ()) do
            yield it.Current
    }

[<EntryPoint>]
let main _ =
    [0; 1]
    |> Seq.collect (duplicate)
    (* |> Seq.toArray // When uncommented - works as expected. *)
    |> passThrough
    |> Seq.iter (fun i -> printf $"{i} ")
    0
Run Code Online (Sandbox Code Playgroud)

Seq.toArray取消注释该调用时,它会产生我期望的结果,即迭代序列管道并打印0 0 1 1。然而,当该行被注释掉后,代码就完成了,没有打印任何内容。

Ben*_*erg 5

我与 F# Slack 的一位专家进行了协商(感谢 RC),并被告知正确的实现passThrough应该如下所示。当 while 循环退出时,枚举器将被正确处理。原始实现的问题在于,枚举器在循环退出之前的某个时间点被释放while(如果有的话)。

let passThrough (sq: seq<_>) =
    seq {
        use it = sq.GetEnumerator ()
        while (it.MoveNext ()) do
            yield it.Current
    }
Run Code Online (Sandbox Code Playgroud)

  • 在原始代码中,枚举器*总是*在使用之前被释放。`use` 保证在函数返回之前调用 `Dispose`,并且在函数返回之前不会使用该序列。至于为什么已处理的枚举器在某些情况下仍然可以工作,您必须深入研究它的实现。 (2认同)