Possible Duplicate:
How to create a type bounded within a certain range
I have the data type:
data Expr = Num Int
| Expression Expr Operator Expr
In the context of the problem, the numbers that (Num Int) will represent are single digit only. Is there a way to ensure that restriction within the type declaration?
Of course we could define a function to test whether the Expr is valid, but it would be nice to have the type system handle it.
You can use an abstract data type with a smart constructor:
If you put this in another module and don’t export the
Digitconstructor, then client code can’t construct values of typeDigitoutside of the range [0,9], but you have to manually wrap and unwrap it to use it. You could define aNuminstance that does modular arithmetic, if that would be helpful; that would also let you use numeric literals to construct Digits. (Similarly forEnumandBounded.)However, this doesn’t ensure that you never try to create an invalid Digit, just that you never do. If you want more assurance, then the manual solution Jan offers is better, at the cost of being less convenient. (And if you define a
Numinstance for that Digit type, it will end up just as “unsafe”, because you’d be able to write42 :: Digitthanks to the numeric literal support you’d get.)(If you don’t know what
newtypeis, it’s basicallydatafor data-types with a single, strict field; a newtype wrapper around T will have the same runtime representation as T. It’s basically just an optimisation, so you can pretend it saysdatafor the purpose of understanding this.)Edit: For the more theory-oriented, 100% solution, see the rather cramped comment section of this answer.