Haskell:为包含在另一种类型中的类型使用正确的实例

时间:2013-07-30 22:26:46

标签: haskell types

假设我们有以下代码,其中有两种类型最终放在另外两种类型中,其中最外面的是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的某些内容我无法理解 - 它可能是什么?

1 个答案:

答案 0 :(得分:5)

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

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

它只是将内部节目再次传递给showsPrec。这表明问题是GHC在使用ListWrap包装它时正在擦除类型变量d。实际上,您也可以将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]"