Conditionally derive Show for existential type parameterized on type constructor
haskell
Solution
This is a deficiency in the Prelude classes. There's a nice way around it though embodied in the `prelude-extras` package. I'll outline it below.
We'd like to create a higher-kinded `Show` class. It looks like this
class Show1 a where
show1 :: Show b => a b -> String
Then we can at least accurately express our desired constraint like
deriving instance Show1 a => Show (X a)
Unfortunately, the compiler does not yet have enough information to achieve this derivation. We need to show that `(Show b, Show1 a)` is enough to derive `Show (a b)`. To do so we'll need to enable some (scary, but sanely-used) extensions
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverlappingInstances #-}
instance (Show b, Show1 a) => Show (a b) where
show = show1
And now that we have that proof the compiler will be able to derive what we need
data X a = forall b . Show b => X (a b)
deriving instance Show1 a => Show (X a)
Problem
Suppose I have a data type like this: ``` {-# LANGUAGE RankNTypes #-} data X a = forall b. Show b => X (a b) ``` I would like to derive `Show (X a)`, but of course I can only do so if there is an instance of `Show (a b)`. I'm tempted to write ``` {-# LANGUAGE StandaloneDeriving #-} deriving instance Show (a b) => Show (X a) ``` but unfortunately the type variable `b` is not available in the instance context because it is bound by the forall. My next attempt was to move the `Show (a b)` context into the forall in the data type definition, like so: ``` data X a = forall b. Show (a b) => X (a b) deriving instance Show (X a) ``` This compiles, but unfortunately now I've lost the ability to construct an `X` with an unshowable `(a b)`. Is there any way to allow `X` to be constructed with any `(a b)`, and then conditionally derive `Show (X a)` only if `(a b)` is showable?