5
votes

Let's say I have a polymorphic type where one of the parameters is a higher-kinded type (* -> *).

data Tricky m = Tricky { numbers :: m Int, genesis :: m String }

Is there a general way of deriving instances for such types without using arcane and unsafe language extensions?

I tried enabling StandaloneDeriving so that I could specify the context:

deriving instance Show (m Int) => Show (Tricky m)

But GHC then complains about the constraint being no smaller than the instance head, and points me in the direction of UndecidableInstances.

To summarise:

1. Should I simply go along with this advice, or is there a better way?

2. Are there any proposals to make this process easier?

3. Is it somehow wrong-headed to want to derive 'higher-kinded' instances? Would it be better to derive instances for a few concrete types instead (eg. Vector, [], Set)

1

1 Answers

8
votes

1. There's nothing unsafe about UndecidableInstances.

There's another way to define Show (Tricky m), which is to require the m satisfies forall a. Show a => Show (m a). This is captured by a typeclass like

class Show1 f where
    showsPrec1 :: Show a => Int -> f a -> ShowS

An even cleverer version of Show1 has been added to base 4.9. It's more general since it can be used to show an m a when a doesn't have a Show a instance.

2. You've found the right bits and pieces for doing this.

3. No, it's right-headed to abstract over even higher-kinded structures like Vector, [], and Set. Monad transformers have the kind (* -> *) -> (* -> *) and abstract over types of kind (* -> *), the same kind as a functor, to produce types with the same kind as a functor. Tricky has kind (* -> *) -> *, it takes something with the same kind as a functor and produces an ordinary data type. I call data types of this kind "Models" since they produce a data type abstracting over how it is put together.