Josh Fischer
Josh Fischer

Reputation: 432

In F#, is it possible to limit the range of values in a single case discriminated union?

In the example below, I want every uint64 to be allowed except zero.

type Foo =
    | Foo of uint64

let foo = Foo(5UL) // OK
let bar = Foo(-1)  // Compiler error
let bad = Foo(0UL) // I want this to be a compiler error

Upvotes: 3

Views: 197

Answers (1)

Jarak
Jarak

Reputation: 982

To the best of my knowledge, you can't directly place bounds on the values (if someone else knows otherwise, please do let us know). I think that is something referred to as 'dependent types', which I don't believe F# supports, at least not currently.

I'm guessing you're already well aware of the following, but for the sake of anyone else taking a look, I'll discuss how you might handle this at runtime: The easiest way to do this I believe would essentially be to make the type private and expose only a getFoo function that does custom validation at that time. Depending on what you want, you would either wrap it in an option or throw an exception when the wrong number is passed in. E.g.

type private FooWithException = 
    | Foo of uint64

let getFooWithException (x: uint64) = 
    if x = 0 then
        failwith "x was zero"
    else
        Foo x

or

type private FooOption = 
    | Foo of uint64 option

let tryGetFoo (x: uint64) = 
    if x = 0UL then
        None
    else
        Some(x)

You may also find this page at F# for Fun and Profit useful.

Upvotes: 4

Related Questions