Is there a "unit" class? Would it be useful?

Yes, it would probably be useful. In fact, all of the slightly incompatible versions of it would be useful! Which is kinda the problem.

It's not clear what such a class would even mean, which makes it hard to actually use, because inevitably you'll hit types where there are multiple choices of a default value, and if it's not immediately clear which one the instance provides, you pretty much lose all benefit of having the class in the first place.

A few examples:

  • For Monoid instances, you'd obviously expect the identity element to be the default. But now you're back to the problem of so many types having two or more sensible Monoid instances. Is the default Integer 0 or 1? For Monoid, the standard library uses newtype wrappers, but those are clumsy and make it difficult to work with the wrapped types--with Monoid it works okay because you get access to mconcat and such, but you can't do anything interesting with just a default value.

  • For Functor-like types with an "empty" value, that gives an obvious default. This is what MonadPlus and Alternative are doing... and also overlaps with Monoid, and if memory serves me there's at least one type where those three instances aren't identical. Which do you pick, when there's more than one choice? Consider lists: You can blindly append them, giving an arbitrary Monoid, with the empty list as identity; but for lists of Monoids you can also zipWith mappend, giving a lifted monoid with repeat mempty as the identity. Many functors have analogous Monoid instances, but not always both--so whichever you pick for lists, you'll be conceptually inconsistent with some other Functor!

  • For unit types like (), it's not hard to pick a default! But what about enumerations? Does it make sense to pick the first constructor? Sometimes, but not always. How will people using the class know?

  • What about Bounded? If none of the above applies, you could use minBound. But some of the above types could be Bounded as well, so you'll confuse matters if their default isn't their minimum value.

Basically, there's just enough overlap that it seems to make sense... but really, you've got at least three different type classes in mind here, and trying to unify them is probably not as helpful as it seems at first.


If you can pin things down a little better and give a clear, consistent semantic interpretation of a "default" value, without just reinventing Monoid or another existing class, such that the type class is easy to use without having to stop and think about what "default" gets chosen, great! But I wouldn't get my hopes up on making it work.

That said, the one obviously sensible case that's not covered by any standard type class is singletons like (). Most of the time these aren't terribly useful--for obvious reasons!--which is probably why there isn't such a class. One place where such a class is extremely useful, though, is when you're doing something involving type-level shenanigans, because such a type represents a single value at both the type and term level--so a class for such types lets you manipulate type-level values freely, then conjure up the term that goes with it, so you can pass it to some other function that might, e.g., select a type class instance based on it. For that reason, I have a class along those lines in my perpetually-incomplete type-hackery library, e.g.:

class TermProxy t where 
    term :: t

-- This makes explicit the lexical pun of () having type ().
instance TermProxy () where 
    term = ()

instance (TermProxy a, TermProxy b) => TermProxy (a, b) where 
    term = (term, term)

I doubt such a class is very useful in any other context, though.


You are looking for some sort of Default type class. While the semantics of what a "default" should be is debatable (and I suggest you accept C.A. McCanns answer for his valuable comments there), you can get a Default class from a fairly commonly used package called data-default.

The class is:

-- | A class for types with a default value.
class Default a where
    -- | The default value for this type.
    def :: a

If you want to avoid a new class, you can define unit in terms of the Enum class:

unit :: Enum a => a
unit = toEnum 0

Or maybe better with the Bounded class:

unit :: Bounded a => a
unit = minBound

Both of these produce the expected result for the unit type (and most likely for any other single constructor type):

*Main> unit :: ()
()

The drawbacks compared to the data-default class (mentioned in another answer) is that there are fewer instances, particularly no instance that returns [] for [a]. Also the result is not what you might expect from some type, especially if you use minBound:

*Main> unit :: Int
-2147483648

*Main> unit :: Char
'\NUL'

*Main> unit :: Bool
False