简体   繁体   English

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

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

Imagine the following code: 想象一下以下代码:

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

Now let us test it: 现在让我们测试一下:

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

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

This works as I would expect. 这可以像我期望的那样工作。 But if we change List to Seq in the function, we get different behavior: 但是如果我们在函数中将List更改为Seq,我们会得到不同的行为:

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

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

Here with keys2 I can see the exception message within values object in the debugger but no exception is thrown... 这里使用keys2我可以在调试器的values对象中看到异常消息,但是没有抛出异常......

Why is it like this? 为什么会这样? I need some similar logic in my app and would prefer to work with sequences. 我的应用程序中需要一些类似的逻辑,并且更喜欢使用序列。

This is a classic example of a problem with side effects and lazy evaluation. 这是副作用和懒惰评估问题的典型示例。 Seq functions such as Seq.map are lazily evaluated, that means that the result of Seq.map will not be computed until the returned sequence is enumerated. Seq.mapSeq函数进行了延迟求值,这意味着在枚举返回的序列之前,不会计算Seq.map的结果。 In your example, this never occurs because you never do anything with values . 在您的示例中,这永远不会发生,因为您从未对values执行任何操作。

If you force the evaluation of the sequence by generating a concrete collection, like a list , you will get your exception and the function will return false : 如果通过生成具体集合(如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

As you've noticed, using List.map instead of Seq.map also resolves your issue because it will be eagerly evaluated when called, returning a new concrete list . 正如您所注意到的,使用List.map而不是Seq.map也可以解决您的问题,因为在调用它时会对其进行热切评估,返回一个新的具体list

The key takeaway is, you have to be really careful about combining side effects with lazy evaluation. 关键的一点是,你必须非常小心将副作用与懒惰评估结合起来。 You can't rely on effects happening in the order that you initially expect. 您不能依赖于您最初期望的顺序发生的效果。

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

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