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