【问题标题】:Seq.iter fails to iterate the sequence created with seq.collect and sequence expressionSeq.iter 无法迭代使用 seq.collect 和序列表达式创建的序列
【发布时间】:2022-01-20 21:48:27
【问题描述】:

我在 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

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

【问题讨论】:

    标签: f#


    【解决方案1】:

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

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

    【讨论】:

    • 我后来也得到了一个可能的解释,说明为什么它在一种情况下有效,但存在缺陷,但在另一种情况下无效。我不会试图传递这一点,但请放心,这是一个合理的解释。
    • 在原始代码中,枚举器在被使用之前总是被释放。 use 保证在函数返回之前调用Dispose,并且在函数返回之前不会使用序列。至于为什么一个废弃的枚举器在某些情况下仍然可以工作,你必须深入研究它的实现。
    • 我相信你可能是对的,所以我改变了答案,至少不与此相矛盾。
    猜你喜欢
    • 2018-10-20
    • 2014-10-12
    • 1970-01-01
    • 2017-02-16
    • 2013-09-03
    • 1970-01-01
    • 1970-01-01
    • 2012-04-19
    • 1970-01-01
    相关资源
    最近更新 更多