簡體   English   中英

F#Func類型推斷Seq和PSeq ToDictionary之間的區別

[英]F# Func type inference difference between Seq and PSeq ToDictionary

給出一個簡單的元組序列,以及使用F#PowerPack的PSeq的並行序列:

let a = Seq.singleton (1,"a")  --> val a: seq<int * string>
let b = a |> PSeq.map id       --> val b: pseq<int * string>

現在我想從它們創建一個.Net BCL字典:

let bd = b.ToDictionary(fst, snd, HashIdentity.Structural)
let ad = a.ToDictionary(fst, snd, HashIdentity.Structural)
let ad2 = a.ToDictionary(fst, snd)
let ad3 = a.ToDictionary((fun (x,y) -> x), (fun (x,y) -> y), HashIdentity.Structural)

雖然let bd工作,但let ad無法編譯,因為它無法推斷類型並正確轉換為BCL的Func。 如果我省略了第三個參數,有趣的是它工作得很好,如let ad2 ,如果我寫出來,或fstsnd手動內嵌在let ad3

該表達式應該具有類型Func <(int * string),'a>但這里有類型'b *'c - >'b

  • 為什么let ad不能編譯,而所有替代方案都可以正常工作?
  • 有沒有辦法let ad編譯,而不提供內聯函數或類型注釋?

PS:我需要HashIdentity.Structural,因為在實際代碼中,鍵不是整數,而是元組或記錄

更新:我現在定義了let dictionary (s : ('a * 'b) seq) = s.ToDictionary((fun (x,y)->x), (fun (x,y)->y), HashIdentity.Structural)所以我可以寫let ad = a |> dictionary ,但我仍然對它為什么不能用fstsnd函數編譯感興趣。

我認為這不是一個錯誤,而只是F#類型推理算法的一個非常難看的角落案例,其中涉及過載和類型定向轉換。 奇怪的是,編譯器正確地推斷出ad2綁定的類型,因為ToDictionary的第二個重載有兩個參數,這會在推理期間導致額外的重載ToDictionary步驟。 另一方面,只有一個帶有三個參數的重載,因此在嘗試推斷ad類型時不會使用重載決策步驟。

正如我所提到的,另一個難題是從F#函數到.NET委托類型的類型定向轉換(這是你可以傳遞一個F#函數,其中Func<_,_>是預期的)。 基本上,如果使用顯式lambda或者存在多個重載,則考慮此轉換,但如果只有一個重載且沒有顯式lambda,則不考慮轉換。 這意味着以下內容也適用:

let ad3 = a.ToDictionary(System.Func<_,_>(fst), 
                         System.Func<_,_>(snd), HashIdentity.Structural)

因為現在不需要執行類型定向轉換。

這個結果肯定是違反直覺的,所以我希望有一些方法可以調整類型推斷算法來更好地處理這些極端情況。 不幸的是,與.NET類型系統的某些方面(例如命名委托類型,子類型,重載等)的互操作使得推理比其他情況更難,並且可能有某些原因該算法不容易修改以處理這種情況。

看起來像一個錯誤(或重載解析邊緣情況),但您可以通過使用內置的dict函數來避免此問題:

let a = Seq.singleton (1,"a")  
let b = a |> PSeq.map id 
let bd = dict b
let ad = dict a

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM