Haskell: Using the correct instance for a type wrapped in another type
haskell, types
Solution
If you look at the derived code (with `-ddump-deriv`) then you can see that the derived instance for `ListWrap` is pretty normal looking
instance Show ListWrap where
showsPrec a (ListWrap b) =
showParen (a >= 11) $ showString "ListWrap " . showsPrec 11 b
it's just passing the inner show down to `showsPrec` again. This suggests that the problem is that GHC is erasing the type variable `d` when you wrap it with ListWrap. Indeed, you could also write `ListWrap` as
data ListWrap where
ListWrap :: forall d. [(WrapperType d)] -> ListWrap
which emphasizes that this is existentially typed.
We can see the error more directly by deleting the `instance Show (WrapperType t)` and observing GHC's type error
/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.
In other words, it has lost the details about the `d` type and thus cannot unify the specific `instance Show (WrapperType SomeType1)`.
Now you would think that this would imply that keeping that type information around would make the type error go away.
data ListWrap d where
ListWrap :: [(WrapperType d)] -> ListWrap d
> show $ ListWrap [WrapperType SomeType1]
"ListWrap [incorrect]"
But it seems like the instance search is going awry as well. The only way I could find to make it work was to turn on `UndecidableInstances` and provide a suggestion for instance derivation.
deriving instance Show (WrapperType d) => Show (ListWrap d)
after which the example works
> show $ ListWrap [WrapperType SomeType1]
"ListWrap [correct]"
Problem
Say we have the following code, where a couple of types end up being place inside two other types, the outer-most of which is a 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 ``` Now, writing `[WrapperType SomeType1]` gives me what I want: ``` *MyModule> [WrapperType SomeType1] [correct] ``` But as soon as I put it inside `ListWrap` I get the wrong `Show` instance picked to display the contents: ``` *MyModule> ListWrap [WrapperType SomeType1] ListWrap [incorrect] ``` There must be something about type classes and/or GADTs that I'm failing to understand -- what could it be?