Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I create a type whose value can only be within a valid range?

Tags:

f#

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?

like image 766
Scott Nimrod Avatar asked Mar 15 '16 05:03

Scott Nimrod


2 Answers

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
like image 163
Random Dev Avatar answered Oct 19 '22 13:10

Random Dev


I'm typically using the static function that returns instance of Result<T, Error>, exceptions are really not a good pattern.

like image 43
Petr Koutny Avatar answered Oct 19 '22 12:10

Petr Koutny