Haskell 异常歧义错误

Haskell 异常歧义错误,haskell,Haskell,在以下代码中,当第(4)行编译没有问题时,为什么第(1)行失败: 我知道DataOrError基本上是或者,这只是为了说明 错误是: 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(

在以下代码中,当第(4)行编译没有问题时,为什么第(1)行失败:

我知道
DataOrError
基本上是
或者
,这只是为了说明

错误是:

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")

您看到一个错误,因为
Show(DataOrError a b)
的派生实例如下所示

instance (Show a, Show b) => Show (DataOrError a b) where
    ...
请注意,
a
b
都必须是
Show
实例,才能有其实例。
x1
x2
的类型是
DataOrError a Int
,对于
e1
e2
而言,类型是
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行,编译器只知道它必须是
numa
。然后,它选择将其默认为
Integer
,起初我将其误解为错误,因为我编译时总是将警告视为错误。

错误和ideone链接现在包括在内。那么为什么第(4)行编译时没有问题,而第(1)行编译时没有问题?实际上,只使用
x1
就可以解决问题,
e1
e2
没有问题地工作。@Clinton为我抛出了一个错误。你使用的是什么版本的GHC?@Clinton噢,没关系,原因是当你有
apply(+)x1 x2
时,类型变量仍然未知,当你有
xN
eN
的混合物时,这两个类型变量都具体化了。如果将完整类型签名添加到
x1
,则第4行将出现错误。至少我查过了。你查过ideone链接了吗?第4行没有错误。@Clinton我不得不承认有点尴尬,我认为这是一个错误,因为我的构建系统在IDE中标记了它,但这只是一个警告。我只是习惯了把警告当作错误对待。如果在GHC中使用
-Wall
进行编译,您将看到变量默认为
Integer
,因为编译器通过使用
(+)
知道它必须是
Num
。如果您有
print(apply(++)e1 e2)
它实际上会抛出一个错误,因为
++
对该类型变量的约束不足以使其成为默认值。
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