在默认方法中对幻像类型的类约束进行编译错误

时间:2017-09-21 18:25:13

标签: haskell compiler-errors typeclass phantom-types

这个(有些荒谬的)模块编译:

{-# 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的插入位置。为什么第二个例子没有编译?

1 个答案:

答案 0 :(得分:2)

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调用可以在任何一个monoid上进行,可能是另一个!

对于该调用,推理引擎生成一个新的x0类型变量,因此类型错误消息: - (

也许应该更新GHC的实例派生机制,现在允许使用模糊类型(这是一件好事,IMO)。

对于更简单的情况,请考虑

a :: forall x. Monoid x => Int
a = undefined

b :: forall x. Monoid x => Int
b = a

在Haskell中,最后一次调用需要消除歧义的显式类型参数。它可以在依赖类型的语言(如Agda / Idris / Coq / ...)中正常工作,因为这些(默认情况下,至少)明确地传递它们的类型参数。