这个(有点 absurd 的)模块编译:
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ExplicitForAll #-}
module Foo where
class A t where
f :: forall x m. Monoid x => t m -> m
f = undefined
instance A [] where
f = undefined
如果我删除实例的
f
定义,我希望它继承方法默认值并达到相同的效果。{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ExplicitForAll #-}
module Foo where
class A t where
f :: forall x m. Monoid x => t m -> m
f = undefined
instance A [] where
但是,这不起作用。 GHC 8.0.2 给出了这个错误:
• Could not deduce (Monoid x0)
arising from a use of ‘Foo.$dmf’
from the context: Monoid x
bound by the type signature for:
f :: Monoid x => [m] -> m
at src/Foo.hs:10:10-13
The type variable ‘x0’ is ambiguous
These potential instances exist:
instance Monoid a => Monoid (IO a) -- Defined in ‘GHC.Base’
instance Monoid Ordering -- Defined in ‘GHC.Base’
instance Monoid a => Monoid (Maybe a) -- Defined in ‘GHC.Base’
...plus 7 others
(use -fprint-potential-instances to see them all)
• In the expression: Foo.$dmf @[]
In an equation for ‘f’: f = Foo.$dmf @[]
In the instance declaration for ‘A []’
我不确定如何阅读这个错误,因为我不知道想象中的
x0
在哪里正在插入。为什么第二个示例不编译?
最佳答案
GHC 基本上是将您的代码转换为:
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ExplicitForAll #-}
module Foo where
defaultF :: forall t x m. (A t, Monoid x) => t m -> m
defaultF = undefined
class A t where
f :: forall x m. Monoid x => t m -> m
f = defaultF @t @x @m
instance A [] where
f = defaultF @[]
现在,在最后一行,类型变量
x
不在范围内,因为我们没有明确的 forall x
.即使是,它也不会传递给 defaultF
作为显式类型参数。所以,最后一个 defaultF
可以在任何幺半群上进行调用,可能是另一个!对于该调用,推理引擎生成一个新的
x0
类型变量,因此类型错误消息:-(也许 GHC 的实例派生机制应该更新,现在允许模棱两可的类型(这是一件好事,IMO)。
对于更简单的情况,考虑
a :: forall x. Monoid x => Int
a = undefined
b :: forall x. Monoid x => Int
b = a
在 Haskell 中,最后一个调用需要一个明确的类型参数。它可以在像 Agda/Idris/Coq/... 这样的依赖类型语言中正常工作,因为这些(至少在默认情况下)显式传递它们的类型参数。
关于haskell - 默认方法中对幻像类型的类约束的编译错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46350839/