9

In Haskell you can define a algebraic data type without a constructor:

data Henk

But what is the purpose of a type (or kind?) that doesn't have a constructor?

Henk
  • 369
  • 3
  • 9
  • 2
    these are called phantom types; they are useful for parametrizing other types, i.e. passing as type parameter to type constructors, none of whose value constructors expect a value parameter of that phantom type. – Erik Kaplun Oct 25 '15 at 22:33
  • 10
    Never mind phantom types (so it's not a duplicate, Erik), there's plenty of sensible motivation for at least one *empty* type: http://stackoverflow.com/q/14131856/828361 – pigworker Oct 25 '15 at 22:41

1 Answers1

14

Type-level machinery often requires types to exist but never constructs values of such types.

E.g., phantom types:

module Example (Unchecked, Checked, Stuff()) where

data Unchecked
data Checked
data Stuff c = S Int String Double

check :: Stuff Unchecked -> Maybe (Stuff Checked)
check (S i s d) = if i>43 && ...
                  then Just (S i s d)
                  else Nothing

readFile :: Filepath -> IO (Stuff Unchecked)
readFile f = ...

workWithChecked :: Stuff Checked -> Int -> String
workWithChecked stuff i = ...

workWithAny :: Stuff any -> Int -> Stuff any
workWithAny stuff i = ...

As long as the S constructor is not exported by the module, the user of this library can not forge the "checked" status on the Stuff data type.

Above, the workWithChecked function does not have to sanitize the input every time it is called. The user must have already done it, since it has to provide a value in the "checked" type -- and this means the user had to call the check function beforehand. This is an efficient and robust design: we do not repeat the same check over and over at every call, and yet we do not allow the user to pass unchecked data.

Note how the values of types Checked,Unchecked are immaterial -- we never use those.

As others mentioned in comments, there are many other uses of empty types than phantom types. For instance, some GADTs involve empty types. E.g.

data Z
data S n
data Vec n a where
  Nil  :: Vec Z a
  Cons :: a -> Vec n a -> Vec (S n) a

Above we use empty types to record length information in types.

Further, types with no constructors are needed to achieve some theoretical properties: if we look for an a such that Either a T is isomorphic to T, we want a to be empty. In type theory, an empty type is commonly used as a type equivalent of a logically "false" proposition.

chi
  • 111,837
  • 3
  • 133
  • 218
  • That's only part of why phantom types are useful. To extend your example: you could also have a few functions that worked fine on either checked or unchecked `Stuff`, and other functions that only worked on the checked version. – Jeremy List Oct 27 '15 at 14:45
  • @JeremyList I totally agree (otherwise, we could simply use two different types instead of a phantom index). I added one more function, to improve a little bit, even the full power of phantom types is not shown here. – chi Oct 27 '15 at 19:28