[英]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.map
等Seq
函數進行了延遲求值,這意味着在枚舉返回的序列之前,不會計算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.