2011-08-01 47 views
5

我有一個文件中記錄的是使用兩個IntMaps:如何使用不同的鍵類型的IntMap?

data Doc = Doc { kernels :: IntMap Kernel, nodes :: IntMap Node } 

但是我發現,從兩個IntMaps按鍵有不同的意義,我不兩個型動物種類分離並沒有得到錯誤,當混合內核類型和節點類型。我想要具有檢查內核映射和節點映射中的密鑰並且不允許混淆的函數。 E.g:

someFunction :: Doc -> KernelKey -> NodeKey -> a 
someFunction doc k1 k2 = ..... 

相反的電流:

someFunction :: Doc -> Int -> Int -> a 
someFunction doc k1 k2 = .... -- warning check twice k1 and k2 

難道是更多鈔票?或者我將從IntMap更改爲Map

感謝

+1

你使用'IntMap'而不是'Map'是什麼原因?如果是性能,那麼你應該考慮'無序容器'(這可能是你最好的解決方案,但值得考慮)。 –

+2

另請參閱有關'IntSet'的相關問題http://stackoverflow.com/questions/5746590/how-to-newtype-in​​tset ...你可能想看看['enummapset' package](http:/ /hackage.haskell.org/package/enummapset),這是我目前使用的 – hvr

回答

10

您可以使用newtype,使周圍Int包裝來區分它們的含義。

newtype KernelKey = KernelKey Int 
newtype NodeKey = NodeKey Int 

someFunction :: Doc -> KernelKey -> NodeKey -> a 
someFunction doc (KernelKey k1) (NodeKey k2) = ... 

這樣的話,你仍然可以使用IntMap內部,但是揭露更多類型安全的接口,特別是如果你還控制KernelKeyNodeKey值是如何被創建的,即你不導出它們的構造,因此用戶只能將它們作爲其他函數的返回值。

請注意,newtype包裝在運行時消失,因此這種額外的包裝和解包不會以任何方式影響性能。

+0

我對性能感到困惑。但是如果包裝在運行時消失,我會使用你的解決方案。 – Zhen

3

您可以創建一個統一的密鑰類型,併爲您的Doc類型包裝IntMap API。它可能看起來像這樣。

data DocValue = DocKernel Kernel 
       | DocNode Node 
data DocKey = KernelKey Int 
      | NodeKey Int 

docLookup :: DocKey -> Doc -> Maybe DocValue 

該解決方案的好處是您只需要每個您需要的地圖API函數的一個副本。這是一個更接近您所擁有的代碼的不同解決方案。

newtype NodeKey = NodeKey Int 
newtype KernelKey = KernelKey Int 
lookupDocNode :: NodeKey -> Doc -> Maybe Node 
lookupDocKernel :: KernelKey -> Doc -> Maybe Kernel 

您也可以在不使用新類型的情況下執行此解決方案。這兩種解決方案都爲您提供安全類型在第一個中你必須指定你想要的類型。在第二個中,您可以通過選擇要調用的函數來指定它。

+0

我不喜歡統一密鑰類型,因爲我總是知道什麼時候可以獲得另一種類型的密鑰。我對結合了這兩個鍵的函數有問題,可能會感到困惑:例如:'lookupNodeHasKernel :: Int - > Int - > Bool' – Zhen

相關問題