You can do this with DataKinds . It may be trickier, but:
{-
I would prefer to use the alternative @MataterialOrchids approach using smart constructors.
EDIT: What DataKinds do.
The DataKinds allows the compiler to automatically create a new type, different from * for each data type that is written, and new types living in this form from the constructors.
So, Nat , in addition to simple ADT, also generates the form Nat and the constructors of types Z :: Nat and S :: Nat -> Nat . This S is comparable to Maybe :: * -> * - it just does not use the type of all types, but your new kind is Nat , populated only by representations of natural numbers.
The fact is that now you can also define type constructors of mixed types. A classic example of this is Vec :
data Vec (n :: Nat) (a :: *) where {-...-}
which has the form Vec :: Nat -> * -> * . Similarly, T has the form T :: Nat -> * . This allows you to use it with a constant of length encoded by type, and leads to a type error when combining two lines of different lengths.
Although it looks extremely powerful, it is actually limited. To get all of these views, Agda should be used depending on the typed languages.
source share