2014-11-20 105 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