I’m on board with giving the programmer a hint that a function might fail, but how do you avoid contaminating the type of other functions? An immediate failwith?
In the following code, f1 and f2 return an Or_error.t even though their caller can do nothing to prevent it. Now our codebase has 3 functions whose return types tell the programmer to be careful but there’s nothing to be careful about when calling the last two.
let divide a b =
if b = 0 then
Error (Error.of_string "Division by zero")
else
Ok (a / b)
let f1 () =
divide 0 0
let f2 () =
f1 ()
So, the way I’d write my code is:
let divide a b =
if b = 0 then
Error (Error.of_string "Division by zero")
else
Ok (a / b)
let f1 () =
match divide 0 0 with
| Ok x -> x
| Error e -> Error.raise e
let f2 () =
f1 ()
Now both f1 and f2 return a plain int and the programmer’s attention is drawn to divide. Is this recommended usage, as opposed to monadic propagation?