5

假设我们有以下代码,其中几个类型最终被放置在另外两个类型中,其中最外层是一个 GADT:

{-# LANGUAGE FlexibleInstances,
             GADTSyntax,
             GADTs,
             OverlappingInstances,
             StandaloneDeriving #-}

data SomeType1 = SomeType1 deriving Show
data SomeType2 = SomeType2 deriving Show

class SomeClass d where

instance SomeClass SomeType1 where
instance SomeClass SomeType2 where

data WrapperType t where
  WrapperType :: (SomeClass t, Show t) => t -> (WrapperType t)

instance Show (WrapperType SomeType1) where
  show (WrapperType d) = "correct"

instance Show (WrapperType t) where
  show (WrapperType d) = "incorrect"

data ListWrap where
  ListWrap :: [(WrapperType d)] -> ListWrap

deriving instance Show ListWrap

现在,写作[WrapperType SomeType1]给了我想要的东西:

*MyModule> [WrapperType SomeType1]
[correct]

但是一旦我把它放进去,ListWrap我就选择了错误的Show实例来显示内容:

*MyModule> ListWrap [WrapperType SomeType1]
ListWrap [incorrect]

一定有一些关于类型类和/或 GADT 的东西我无法理解——它可能是什么?

4

1 回答 1

5

如果您查看派生代码(带有-ddump-deriv),那么您可以看到派生实例的ListWrap外观非常正常

instance Show ListWrap where
  showsPrec a (ListWrap b) =
    showParen (a >= 11) $ showString "ListWrap " . showsPrec 11 b

它只是再次传递内部表演showsPrec。这表明问题在于,d当您使用 ListWrap 包装类型变量时,GHC 正在擦除类型变量。事实上,你也可以ListWrap写成

data ListWrap where
  ListWrap :: forall d. [(WrapperType d)] -> ListWrap

它强调这是存在类型的。

我们可以通过删除instance Show (WrapperType t)并观察GHC的类型错误更直接地看到错误

/Users/tel/tmp/foo.hs:33:52: Warning:
    No instance for (Show (WrapperType d))
      arising from a use of `showsPrec'
    Possible fix:
      add an instance declaration for (Show (WrapperType d))
    In the second argument of `(.)', namely `showsPrec 11 b'
    In the second argument of `($)', namely
      `showString "ListWrap " . showsPrec 11 b'
    In the expression:
      showParen (a >= 11) $ showString "ListWrap " . showsPrec 11 b
Ok, modules loaded: Main.

换句话说,它丢失了关于d类型的细节,因此无法统一具体的instance Show (WrapperType SomeType1).


现在您会认为这意味着保留该类型信息会使类型错误消失。

data ListWrap d where
  ListWrap :: [(WrapperType d)] -> ListWrap d

> show $ ListWrap [WrapperType SomeType1]
"ListWrap [incorrect]"

但似乎实例搜索也出了问题。我能找到使其工作的唯一方法是打开UndecidableInstances并提供实例推导的建议。

deriving instance Show (WrapperType d) => Show (ListWrap d)

之后该示例有效

> show $ ListWrap [WrapperType SomeType1]
"ListWrap [correct]"
于 2013-07-30T22:50:36.977 回答