为什么GHCi不会在此错误消息中显示多态类型?

时间:2017-06-05 14:33:57

标签: haskell types ghci

我将类型Num a => a -> a的变量类型归为Int,这会引发错误,如预期的那样。但是,错误并不完全符合我的预期。

GHCI

λ> let x = typeInference 1
λ> :t x
x :: Num a => a -> a
λ> x :: Int

<interactive>:141:1: error:
    • Couldn't match expected type 'Int'
                  with actual type 'Integer -> Integer'
    • Probable cause: 'x' is applied to too few arguments
      In the expression: x :: Int
      In an equation for 'it': it = x :: Int
λ>

typeInferance定义

typeInference :: Num a => a -> a -> a
typeInference x y = x + y + 1

我希望错误消息说with actual type 'Num a => a -> a',这是多态类型,为什么不呢?这与GHCi的类型默认有关吗?

1 个答案:

答案 0 :(得分:4)

这确实是因为GHCi's type defaulting

section 4.3.4 of the Haskell 2010 Report中描述了相关规则,这一部分特别相关:

  

每个默认值变量都被默认列表中的第一个类型替换,该类型是所有不明确变量类的实例。如果没有找到这样的类型,则是静态错误。

每个可默认的变量都被默认的变量替换,这是在生成错误消息之前发生的操作。

类型默认必须在类型检查之前发生,当存在不明确的类型时。特别是,如果类型类约束被保留而不是默认,则表达式x :: Int将具有不明确的类型,如

中所定义
  

我们说表达式e有一个模糊的类型,如果它的类型为“u”。 cx⇒t,你有一个类型变量u&#39;发生在cx但不发生在t中。这些类型无效。

(摘自Haskell 2010年度报告,用u'替换为overbar。

因为,如果类型有效,整个表达式将有一个类型变量(受Num限制的那个),它不会出现在结果类型(Int)中(和类型变量)不能统一的),默认必须在类型检查之前发生。

通过认识到我们是类型检查

,这可以更加明确
(x :: forall a. Num a => a -> a) :: Int

看起来,在统一期间,如果最外层的类型构造函数不匹配(左侧是(->)而右侧是Int),它必须是默认值,因为它不能自动深入统一(如果右侧最外面的类型构造函数也是(->)),可以自动进行。

以下是我测试过的一些遵循此行为的示例:

ghci> :set -XExplicitForAll
ghci> (x :: forall a. Num a => a -> a) :: Char -> Char  -- Outermost constructor matches, so 'a' can get unified with Char and the 'a' type variable disappears

<interactive>:5:2: error:
    • No instance for (Num Char)
        arising from an expression type signature
    • In the expression:
          (x :: forall a. Num a => a -> a) :: Char -> Char
      In an equation for ‘it’:
          it = (x :: forall a. Num a => a -> a) :: Char -> Char
ghci> (x :: forall a. Num a => a -> a) :: Maybe Char

<interactive>:8:2: error:
    • Couldn't match expected type ‘Maybe Char’
                  with actual type ‘Integer -> Integer’
    • In the expression: (x :: forall a. Num a => a -> a) :: Maybe Char
      In an equation for ‘it’:
          it = (x :: forall a. Num a => a -> a) :: Maybe Char
ghci> (x :: forall a. Num a => a -> a) :: Either Char Bool

<interactive>:10:2: error:
    • Couldn't match expected type ‘Either Char Bool’
                  with actual type ‘Integer -> Integer’
    • In the expression:
          (x :: forall a. Num a => a -> a) :: Either Char Bool
      In an equation for ‘it’:
          it = (x :: forall a. Num a => a -> a) :: Either Char Bool
ghci> (x :: forall a. Num a => (,) a a) :: Either Char Bool

<interactive>:11:2: error:
    • Couldn't match expected type ‘Either Char Bool’
                  with actual type ‘(Integer, Integer)’
    • In the expression:
          (x :: forall a. Num a => (,) a a) :: Either Char Bool
      In an equation for ‘it’:
          it = (x :: forall a. Num a => (,) a a) :: Either Char Bool
ghci> (x :: forall a. Num a => (,) a a) :: Char

<interactive>:12:2: error:
    • Couldn't match expected type ‘Char’
                  with actual type ‘(Integer, Integer)’
    • In the expression: (x :: forall a. Num a => (,) a a) :: Char
      In an equation for ‘it’:
          it = (x :: forall a. Num a => (,) a a) :: Char