2010-01-31 58 views
36

我這樣做在GHCI如下:Haskell模糊發生 - 如何避免?

:m + Data.Map 
let map = fromList [(1, 2)] 
lookup 1 map 

GHCI知道地圖是(地圖整數整數)。那麼爲什麼它聲明Prelude.lookup和Data.Map.lookup之間的類型是明確的,我能避免嗎?

<interactive>:1:0: 
    Ambiguous occurrence `lookup' 
    It could refer to either `Prelude.lookup', imported from Prelude 
          or `Data.Map.lookup', imported from Data.Map 

> :t map 
map :: Map Integer Integer 
> :t Prelude.lookup 
Prelude.lookup :: (Eq a) => a -> [(a, b)] -> Maybe b 
> :t Data.Map.lookup 
Data.Map.lookup :: (Ord k) => k -> Map k a -> Maybe a 

回答

46

的類型顯然是不同的,但哈斯克爾不允許名臨時超載,所以你只能選擇一個lookup沒有前綴使用。

典型的解決方案是導入Data.Map合格:

> import qualified Data.Map as Map 

那麼你可以說

> lookup 1 [(1,2), (3,4)] 
Just 2 
> Map.lookup 1 Map.empty 
Nothing 

通常,哈斯克爾圖書館要麼避免重複使用的名字從前奏,否則再利用一大堆他們。 Data.Map是第二個,作者希望你導入它合格。

[編輯包括ephemient的評論]

如果你想使用Data.Map.lookup沒有前綴,你要隱藏Prelude.lookup因爲它隱含進口否則:

import Prelude hiding (lookup) 
import Data.Map (lookup) 

這是一個有點怪異,但可能如果你使用Data.Map.lookup一大堆,並且你的數據結構都是地圖,那麼永遠不會存在。

18

在一個稍微更廣泛的注意,這是一件困惑我在第一 - 這樣,讓我重申和強調的東西彌敦道桑德斯說:

哈斯克爾不允許名臨時超載

這是默認的事實,但起初似乎令人驚訝的非顯而易見的。 Haskell中允許兩個樣式polymorphic functions

  • 參數多態,它允許一個函數來在結構上是相同的,抽象的方式上的任意類型的操作
  • 特設多態,它允許一個函數操作在結構上不同但有希望語義相同的任何一組定義的類型

參數多態性是Haskell a中的標準(並且是給定選擇的首選)方法nd相關語言; ad-hoc多態是大多數其他語言的標準,通過諸如「函數重載」之類的名稱來實現,並且通常在實踐中通過編寫具有相同名稱的多個函數來實現。

特設多態是在Haskell能夠通過類型類,這就需要類與所有與其相關的特設多態函數定義和實例明確聲明由重載使用的類型。在實例聲明之外定義的函數絕不是特別多態的,即使它們的類型足夠明確,以至於引用將是明確的。

因此,當在不同模塊中定義多個具有相同名稱的非類型類函數時,如果嘗試使用任一函數,導入兩個不合格模塊將導致錯誤。 Data.List,Data.MapData.Set的組合在這方面特別令人震驚,並且由於部分Data.List是由Prelude導出的,所以標準做法(如Nathan Sanders所述)總是導入其他合格的人。

+0

這是我尋求的答案,+1。但我還有一個問題。那麼爲什麼所有這些'Data.List','Data.Set'等都沒有「容器」類型類?或者如果有(如果我理解正確,這是'Functor'類型類型) - 那麼,爲什麼爲容器類型定義它的實例並不是在庫中無處不在? – ulidtko 2012-02-15 03:33:16

+0

@ulidtko:簡短的回答是「因爲它比聽起來更難」,而長的回答不適合評論。什麼容器支持什麼操作和對元素類型的限制有很多複雜性,&c。查找'TypeFamilies'擴展的信息 - 容器API是一個激勵的例子。 – 2012-02-15 16:02:58

+3

@ulidtko這可能對你很有趣:http://hackage.haskell.org/packages/archive/classy-prelude/0.4.1/doc/html/ClassyPrelude.html – 2012-12-07 07:55:20