繁体   English   中英

F# - 为什么Seq.map不传播异常?

[英]F# - Why Seq.map does not propagate exceptions?

想象一下以下代码:

let d = dict [1, "one"; 2, "two" ]

let CollectionHasValidItems keys =
    try
        let values = keys |> List.map (fun k -> d.Item k)
        true
    with
        | :? KeyNotFoundException -> false

现在让我们测试一下:

let keys1 = [ 1 ; 2 ]
let keys2 = [ 1 ; 2; 3 ]

let result1 = CollectionHasValidItems keys1 // true
let result2 = CollectionHasValidItems keys2 // false

这可以像我期望的那样工作。 但是如果我们在函数中将List更改为Seq,我们会得到不同的行为:

let keys1 = seq { 1 .. 2 } 
let keys2 = seq { 1 .. 3 }

let result1 = CollectionHasValidItems keys1 // true
let result2 = CollectionHasValidItems keys2 // true

这里使用keys2我可以在调试器的values对象中看到异常消息,但是没有抛出异常......

为什么会这样? 我的应用程序中需要一些类似的逻辑,并且更喜欢使用序列。

这是副作用和懒惰评估问题的典型示例。 Seq.mapSeq函数进行了延迟求值,这意味着在枚举返回的序列之前,不会计算Seq.map的结果。 在您的示例中,这永远不会发生,因为您从未对values执行任何操作。

如果通过生成具体集合(如list强制对序列进行求值,则会得到异常并且函数将返回false

let CollectionHasValidItems keys =
    try
        let values = keys |> Seq.map (fun k -> d.Item k) |> Seq.toList
        true
    with
        | :? System.Collections.Generic.KeyNotFoundException -> false

正如您所注意到的,使用List.map而不是Seq.map也可以解决您的问题,因为在调用它时会对其进行热切评估,返回一个新的具体list

关键的一点是,你必须非常小心将副作用与懒惰评估结合起来。 您不能依赖于您最初期望的顺序发生的效果。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM