2017-08-27 20 views
1

的一個實例的「模糊類型變量」錯誤我正在學習Haskell並試圖使我的數據(與Maybe類似)爲Eq的實例,如下所示。Haskell - 使我的數據成爲Eq

module Main where 

data MyMaybe a = MyNothing | MyJust a 

instance (Eq a) => Eq (MyMaybe a) where 
    MyNothing == MyNothing = True 
    MyJust x == MyJust y = x == y 
    _ == _ = False 

main :: IO() 
main = do 
    let b0 = MyJust 42 == MyJust 42 -- OK 
    print b0      -- True 
    let b1 = MyNothing == MyNothing -- Build error! 
    print b1 

但是編譯器在行let b1 = MyNothing == MyNothing中返回錯誤,如下所示。

?由於使用'==' 而產生的不明確的類型變量'a0'防止約束'(Eq a0)'被解決。 可能的修正:使用類型註釋來指定'a0'應該是什麼。 這些潛在的情況下存在: 例如公式排序 - 在定義「GHC.Classes」

...

我怎樣才能解決呢?

...我搜索了現有的問題和答案。下面的一個看起來很接近我,但我認爲我的代碼已經解決了答案提出的問題。

how to instance Eq without deriving

+0

它具體與MyMaybe有關,你會得到與標準Maybe相同的結果。 [演示](https://ideone.com/VOeZak)。 –

回答

2

的問題是,MyMaybe是parametrised類型,但在表達MyNothing == MyNothing,編譯器不能計算出,如果你的意思是MyMaybe IntMyMaybe StringMyMaybe (Int -> Bool),或別的東西。

您可以用類型標註像這樣幫助它:

let b1 = MyNothing == (MyNothing :: MyMaybe Int) 
1

的問題是,MyNothing已與什麼a可以沒有限制型MyMaybe a

當你寫MyNothing == MyNothing,那麼(==) :: (Eq b) => b -> b -> Bool類型限制兩個MyNothing具有相同類型(編譯器最初開始時與MyNothing :: MyMaybe a0MyNothing :: MyMaybe a1,但後來意識到a0 == a1)。

但要解決==本身,編譯器需要找到正確的Eq實例(因爲那裏的==已定義)。我們的類型是MyMaybe a,這很好:我們有一個Eq (MyMaybe a)實例。但是它也需要一個Eq a實例,因爲我們不知道a是什麼,所以無法解決。 ((Eq a)沒有在MyNothing == MyNothing的情況下實際使用並不重要;類型檢查沒有關注運行時的值。)

這是編譯器放棄的地方,它說它無法解析約束(Eq a0),因爲類型變量a0不明確。


解決這個問題很簡單。只要給編譯器哪種類型應該使用提示:

let b1 = MyNothing == (MyNothing :: MyMaybe Integer) -- for example 

或者:

let b1 = MyNothing == (MyNothing :: MyMaybe (Double, [String])) 

實際類型並不重要(只要它有一個Eq實例)。


這種含糊不限於您的MyMaybe類型。您應該得到與MaybeNothing == Nothing)或[][] == [])相同的錯誤。在所有情況下都涉及多態常數(Nothing :: Maybe a,[] :: [a])。


你的例子確實在ghci中有效。這是因爲ghci使用extended defaulting rules並最終將a轉換爲();即比較完成爲MyNothing == (MyNothing :: MyMaybe())