(Moving discussion to mailing list.)
This is a good example that helps us evaluate one of our criteria. For everyone's sake, the summary is: In master, we have:
Range.make : int -> int -> Range.t Result.t
However, according to our proposal we should just return Range.t and not even check the precondition. The argument is the precondition is easy to check, so the client should check it themselves and the implementation of `make` shouldn't do any checking. This seems odd to me. I would much rather call the function make_unsafe in that case, which I did define too.
If we return an abstract (or private) type, I think we should guarantee its invariants hold. Otherwise, there's little point in making it abstract (or private). If we'll return a potentially invalid value, it should only be if the programmer really explicitly asks for that possibility, e.g. by calling a function with an _unsafe suffix.
This example is a little different than int_of_string, which I think would be okay to define as:
int_of_string: string -> int
The reason is the implementation will naturally fail to return an int unless you really can do the conversion correctly. So at least you'll get an exception.