I would use a single case union type to wrap the integer.
I would put the type in its own module and access it through factory and getter methods like so:
module IntsWithoutZero =
// make the type constructor private
type T = private IntsWithoutZero of int
// factory that can apply the constraints
let create value =
// do check for zero here
match value with
| 0 -> None
| _ -> IntsWithoutZero(value) |> Some
// a method to extract the private data
let value (IntsWithoutZero v) = v
// ================== later in the code ==================
// create the type
let myInt = 5 |> IntsWithoutZero.create
// ================== later when used ==================
let myDividedValue =
match myInt with
| None -> None
| Some(v) ->
// get value out
let d = (v |> IntsWithoutZero.value)
// do something zero cannot do
Some(10 / d)
If you wanted to avoid option
, alternatively you could throw an exception in the IntsWithoutZero.create
method if the user supplied zero as a parameter.
Here is a blog post by Scott that does a much better job explaining this concept:
http://fsharpforfunandprofit.com/posts/designing-with-types-single-case-dus/
I hope this helps!