There is famous example of the type level natural numbers:
data Zero
data Succ n
I have a question about desirable restriction when we applying type constructor Succ
. For example, if we want to make such restriction in function definition, we can use the class and context, like in this code:
class Nat n where
toInt :: n -> Int
instance Nat Zero where
toInt _ = 0
instance (Nat n) => Nat (Succ n) where
toInt _ = 1 + toInt (undefined :: n)
It's impossible to use toInt (undefined :: Succ Int)
, it's ok.
But how to realize similar restrictions on type level constructions (perhaps with some advanced type extensions)?
For instance, I'd like to permit using of type constructor Succ
only with type Zero
and with something, like this: Succ (Succ Zero)
, Succ (Succ (Succ Zero))
and so on.
How to avoid such bad example on compile time:
type Test = Succ Int
(for now, there is no compilation error)
P.S.: It is more interesting for me how to create a restriction on the type declaration of the last sample