簡體   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