I am creating a module-level alias for the int type, right? How can I guarantee evenness of values with this kinda wrapper type that should add more constraints on the value? Obviously, the value constructor should be responsible for such a check. Can I define a constructor function even () and guarantee that all values of type even are created using the even () constructor that performs a check for evenness? What is OCaml’s idiomatic approach to do stuff like that?
Note 1: Of course, even: int -> even is not possible or requires exceptions that I’m trying to avoid at any cost, so that and the return value should be of type even option, but it is not important detail here.
Note 2: I have no real problem that I’m solving. I just want to discuss the approach of how to work with such value restrictions in OCaml on type/meta level.
The simplest approach is simply to make even abstract. That way you can control exactly how values of that type are constructed. For example, if you define
module Even : sig
type even
val even : int -> even option
val to_int : even -> int
end = struct
type even = int
let even n = if n mod 2 = 0 then Some n else None
let to_int n = n
end
then the only way to construct values of type even is to go via the Even.even function.
In addition to what @nojb explains, I think it is a case where you may like to declare a private type abbreviation in the signature:
type even = private int
so that you can write (x :> int) instead of Even.to_int x. This is very close to the example given in section 3.2 Private type abbrevations of the manual.