从this question跟进,我不确定为什么这两个代码段会产生完全不同的错误:
f :: a -> b
f x = x
-- Couldn't match expected type `b' with actual type `a'
-- In the expression: x
g :: Monad m => a -> m b
g x = return x
-- Could not deduce (a ~ b) from the context (Monad m)
-- In the first argument of `return', namely `x'.
引起这种行为的规则是什么?
对于熟悉标准Haskell的人来说,它的可读性不高;等式约束(a ~ b)
需要语言扩展。
请注意,正如chi所指出的,仅仅存在约束会触发约束错误:
class C a
h :: C a => a -> b
h x = x
-- Could not deduce...
(空约束() => a -> b
给出匹配而不是约束错误。)
答案 0 :(得分:6)
我认为这不是一个简短的答案,而是要深入了解GHC的内部结构,以了解原因。
如果使用-ddump-tc-trace
开关运行GHC,则可以获得相当长的类型检查过程日志。特别是,如果您在此代码上运行它:
f :: a -> b
f x = x
class C a
h :: C c => c -> d
h x = x
你可以看到,在两种情况下,类型检查a
与b
以及类型检查c
与d
的进展方式完全相同,最终导致以下两个未解决的约束(输出来自GHC 7.8.2):
tryReporters { [[W] cobox_aJH :: c ~ d (CNonCanonical)]
...
tryReporters { [[W] cobox_aJK :: a ~ b (CNonCanonical)]
通过在TcErrors
中更多地关注兔子洞,你可以看到,对于skolems的同等性,tryReporters
最终会通过misMatchOrCND
创建错误消息,该消息具有明确性空上下文的特例:
misMatchOrCND :: ReportErrCtxt -> Ct -> Maybe SwapFlag -> TcType -> TcType -> SDoc
-- If oriented then ty1 is actual, ty2 is expected
misMatchOrCND ctxt ct oriented ty1 ty2
| null givens ||
(isRigid ty1 && isRigid ty2) ||
isGivenCt ct
-- If the equality is unconditionally insoluble
-- or there is no context, don't report the context
= misMatchMsg oriented ty1 ty2
| otherwise
= couldNotDeduce givens ([mkTcEqPred ty1 ty2], orig)