为什么 GHCi 没有在此错误消息中显示多态类型?
How come GHCi doesn't display the polymorphic type in this error message?
我将类型为 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
λ>
类型推理定义
typeInference :: Num a => a -> a -> a
typeInference x y = x + y + 1
我以为错误消息会说 with actual type 'Num a => a -> a'
,这是多态类型,为什么不是呢?这与 GHCi 的默认类型有关吗?
这确实是因为GHCi's type defaulting.
相关规则在 section 4.3.4 of the Haskell 2010 Report 中描述,这部分特别相关:
Each defaultable variable is replaced by the first type in the default list that is an instance of all the ambiguous variable’s classes. It is a static error if no such type is found.
每个可默认的变量都被替换为它的默认值,这是在产生错误消息之前发生的操作。
当类型不明确时,类型默认必须发生在类型检查之前。特别是,如果保留类型 class 约束而不是默认约束,则表达式 x :: Int
中的类型将有歧义,如
中所定义
We say that an expression e has an ambiguous type if, in its type ∀ u'. cx ⇒ t, there is a type variable u in u' that occurs in cx but not in t. Such types are invalid.
(摘自 Haskell 2010 年报告,将 u 替换为带 u'
的上划线)。
因为,如果类型有效,则整个表达式将有一个类型变量(受 Num
约束的变量)不会出现在结果类型 (Int
) 中(并且type variable cannot be unified away), defaulting must be occur here before the type checking.
这可以通过意识到我们正在进行类型检查而变得更明确一些
(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
我将类型为 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
λ>
类型推理定义
typeInference :: Num a => a -> a -> a
typeInference x y = x + y + 1
我以为错误消息会说 with actual type 'Num a => a -> a'
,这是多态类型,为什么不是呢?这与 GHCi 的默认类型有关吗?
这确实是因为GHCi's type defaulting.
相关规则在 section 4.3.4 of the Haskell 2010 Report 中描述,这部分特别相关:
Each defaultable variable is replaced by the first type in the default list that is an instance of all the ambiguous variable’s classes. It is a static error if no such type is found.
每个可默认的变量都被替换为它的默认值,这是在产生错误消息之前发生的操作。
当类型不明确时,类型默认必须发生在类型检查之前。特别是,如果保留类型 class 约束而不是默认约束,则表达式 x :: Int
中的类型将有歧义,如
We say that an expression e has an ambiguous type if, in its type ∀ u'. cx ⇒ t, there is a type variable u in u' that occurs in cx but not in t. Such types are invalid.
(摘自 Haskell 2010 年报告,将 u 替换为带 u'
的上划线)。
因为,如果类型有效,则整个表达式将有一个类型变量(受 Num
约束的变量)不会出现在结果类型 (Int
) 中(并且type variable cannot be unified away), defaulting must be occur here before the type checking.
这可以通过意识到我们正在进行类型检查而变得更明确一些
(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