All well and good! Now we could just have two functions, one which returns IO () and the other which returns IO Int, but it seems a shame to pollute the namespace. Instead it would be nice if we could say e.g.:

A polymorphic wrapper

Having seen that sqrt can choose different code in different contexts, let’s try to write a combinator which either passes a value unchanged, or converts it to ().

By analogy with sqrt consider combining:

toId :: a -> a
toUnit :: a -> ()

Although the first equation both accepts and returns the same type, the second doesn’t. So it makes sense to invent a type class with two parameters. On a technical level, this means we’ll need the MultiParamTypeClasses1GHC extension.

Here’s a suitable type class:

class OrUnit b a where
orUnit :: a -> b

We also need a couple of instances:

instance OrUnit () a where
orUnit a = ()
instance OrUnit a a where
orUnit a = a

In the first instance above, the () is a concrete type rather than a variable, so we’ll also need the FlexibleInstances2 extension.