How do I write, “if typeclass a, then a is also an instance of b by this definition.”

I wish to vigorously disagree with the broken solutions posed thus far.

instance MyClass a => Show a where
    show a = myShow a

Due to the way that instance resolution works, this is a very dangerous instance to have running around!

Instance resolution proceeds by effectively pattern matching on the right hand side of each instance’s =>, completely without regard to what is on the left of the =>.

When none of those instances overlap, this is a beautiful thing. However, what you are saying here is “Here is a rule you should use for EVERY Show instance. When asked for a show instance for any type, you’ll need an instance of MyClass, so go get that, and here is the implementation.” — once the compiler has committed to the choice of using your instance, (just by virtue of the fact that ‘a’ unifies with everything) it has no chance to fall back and use any other instances!

If you turn on {-# LANGUAGE OverlappingInstances, IncoherentInstances #-}, etc. to make it compile, you will get not-so-subtle failures when you go to write modules that import the module that provides this definition and need to use any other Show instance. Ultimately you’ll be able to get this code to compile with enough extensions, but it sadly will not do what you think it should do!

If you think about it given:

instance MyClass a => Show a where
    show = myShow

instance HisClass a => Show a where
    show = hisShow

which should the compiler pick?

Your module may only define one of these, but end user code will import a bunch of modules, not just yours. Also, if another module defines

instance Show HisDataTypeThatHasNeverHeardOfMyClass

the compiler would be well within its rights to ignore his instance and try to use yours.

The right answer, sadly, is to do two things.

For each individual instance of MyClass you can define a corresponding instance of Show with the very mechanical definition

instance MyClass Foo where ...

instance Show Foo where
    show = myShow

This is fairly unfortunate, but works well when there are only a few instances of MyClass under consideration.

When you have a large number of instances, the way to avoid code-duplication (for when the class is considerably more complicated than show) is to define.

newtype WrappedMyClass a = WrapMyClass { unwrapMyClass :: a }

instance MyClass a => Show (WrappedMyClass a) where
    show (WrapMyClass a) = myShow a

This provides the newtype as a vehicle for instance dispatch. and then

instance Foo a => Show (WrappedFoo a) where ...
instance Bar a => Show (WrappedBar a) where ...

is unambiguous, because the type ‘patterns’ for WrappedFoo a and WrappedBar a are disjoint.

There are a number of examples of this idiom running around in the the base package.

In Control.Applicative there are definitions for WrappedMonad and WrappedArrow for this very reason.

Ideally you’d be able to say:

instance Monad t => Applicative t where
    pure = return
    (<*>) = ap 

but effectively what this instance is saying is that every Applicative should be derived by first finding an instance for Monad, and then dispatching to it. So while it would have the intention of saying that every Monad is Applicative (by the way the implication-like => reads) what it actually says is that every Applicative is a Monad, because having an instance head ‘t’ matches any type. In many ways, the syntax for ‘instance’ and ‘class’ definitions is backwards.

Leave a Comment