How can I create a type whose value can only be within a valid range?
Most statically typed languages provide numeric types in which each type supports a range of values.
An int is an example of such type.
To support the following:
Make illegal states unrepresentable
How can I create a type such that a value assignment that's out-of-range results in an error at compile-time?
For example: Type PositiveInteger // range is 0 to 2,147,483,647
UPDATE
I attempted this:
type PositiveInteger = private PInt of int with
static member FromInt i =
if i <= 0 then failwith "out of range" else PInt i
let isSuccessful =
PInt -1
However, the above code still compiles when I want it to throw "out of range" at compile time. Is it fair to say that this isn't supported for compile time?
let's keep at this example (and extend it to mean positive p <=> p > 0)
You can always go and use some math (here using slight modification of the peano axioms to define positive natural numbers):
type PositiveInteger =
| One
| Succ of PositiveInteger
which would have a greater range
of course this is a bit hard to use:
let one = One
let two = Succ one
...
let rec add a b =
match (a,b) with
| (One, b) -> Succ b
| (Succ a, b) -> Succ (add a b)
and this is usually not efficient enough (although it is commonly used on the type-level ... if the language supports it)
So probably most people would use the fail-fast approach with some kind of smart constructor:
type PositiveInteger = private PInt of int with
static member FromInt i =
if i <= 0 then failwith "out of range" else PInt i
this one should compile too if you misslike the with
:
type PositiveInteger =
private | PInt of int
static member FromInt i =
if i <= 0 then failwith "out of range" else PInt i
I'm typically using the static function that returns instance of Result<T, Error>
, exceptions are really not a good pattern.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With