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?

Original source