2014-11-20 109 views
0

在下面的代碼(ideone link),爲什麼線(1)當行(4)編譯沒有問題(ideone link with line (1) commented)失敗:不尋常的曖昧錯誤

data DataOrError a b = Error a | Data b deriving Show 

apply f (Data x) (Data y) = Data (f x y) 
apply f (Data x) [email protected](Error _) = y 
apply f [email protected](Error _) _ = x 

main = do 
    print (apply (+) x1 x2) -- (1) 
    print (apply (+) x1 e2) -- (2) 
    print (apply (+) e1 x2) -- (3) 
    print (apply (+) e1 e2) -- (4) 
    where 
    x1 = Data (2 :: Int) 
    x2 = Data (3 :: Int) 
    e1 = Error ("First thing failed") 
    e2 = Error ("Second thing failed") 

我知道DataOrError基本上是Either,這只是爲了說明。

的錯誤是:

prog.hs:8:3: 
    No instance for (Show a0) arising from a use of `print' 
    The type variable `a0' is ambiguous 
    Possible fix: add a type signature that fixes these type variable(s) 
    Note: there are several potential instances: 
     instance (Show a, Show b) => Show (DataOrError a b) 
     -- Defined at prog.hs:1:50 
     instance Show Double -- Defined in `GHC.Float' 
     instance Show Float -- Defined in `GHC.Float' 
     ...plus 24 others 
    In a stmt of a 'do' block: print (apply (+) x1 x2) 
    In the expression: 
     do { print (apply (+) x1 x2); 
      print (apply (+) x1 e2); 
      print (apply (+) e1 x2); 
      print (apply (+) e1 e2) } 
    In an equation for `main': 
     main 
      = do { print (apply (+) x1 x2); 
       print (apply (+) x1 e2); 
       print (apply (+) e1 x2); 
       .... } 
      where 
       x1 = Data (2 :: Int) 
       x2 = Data (3 :: Int) 
       e1 = Error ("First thing failed") 
       e2 = Error ("Second thing failed") 
+0

什麼是錯誤? – bheklilr 2014-11-20 21:26:13

+0

現在包含錯誤和ideone鏈接 – Clinton 2014-11-20 21:31:54

回答

2

因爲Show (DataOrError a b)派生實例看起來像

instance (Show a, Show b) => Show (DataOrError a b) where 
    ... 

注意兩個ab必須Show實例爲DataOrError到你看到一個錯誤有它的實例。 x1x2的類型是DataOrError a Inte1e2的類型是DataOrError String b。這意味着DataOrError的其他類型變量不限於Show。你可以用顯式類型參數解決這個問題:

main :: IO() 
main = do 
    print (apply (+) x1 x2) -- (1) 
    print (apply (+) x1 e2) -- (2) 
    print (apply (+) e1 x2) -- (3) 
    print (apply (+) e1 e2) -- (4) 
    where 
    x1 = Data 2      :: DataOrError String Int 
    x2 = Data 3      :: DataOrError String Int 
    e1 = Error "First thing failed" :: DataOrError String Int 
    e2 = Error "Second thing failed" :: DataOrError String Int 

你可以把任何東西在那裏,包括(),對你不使用,只要它是Show實例的類型變量。發生這種情況的唯一原因是編譯器試圖提供幫助,並推斷出你沒有指定的參數比你想要的參數更普遍。雖然你可以說它應該不重要,但編譯器不會查看這些值來確定是否可以打印某些內容,而是查看這些類型。

爲什麼你在第4行看不到錯誤,而是在第1行做錯誤是因爲違約。對於第2行和第3行,它可以計算出apply (+)的返回值的完整類型,但在第4行,編譯器只知道它必須是Num a。然後它會選擇將其默認爲Integer,我首先將其誤解爲錯誤,因爲我總是將警告編譯爲錯誤。

+0

那麼爲什麼第(4)行沒有問題而不是(1)編譯?實際上,只用'x1'來解決問題,'e1'和'e2'沒有問題。 – Clinton 2014-11-20 21:36:55

+0

@Clinton爲我引發一個錯誤。你使用什麼版本的GHC? – bheklilr 2014-11-20 21:37:47

+0

http://ideone.com/vqfZko正常工作 – Clinton 2014-11-20 21:39:02