I have a doubt in exceptions. I define a function foo as follows:
let bar _ = raise (MyException “Hello”);;
let foo n = bar (n+1);;
The following code compiles without error
try
foo 5
with MyException h → print_endline h
and the compiler infers the types of bar and foo as
val bar : 'a → 'b =
val foo : int → 'a =
But the following code compiles with error:
let Fibonacci (n : int) : int = failwith “not implemented”
try
fibonacci 10
with Failure _ → print_endline “not implemented”
I understand that in the fibonacci case, the try .. with expression has type unit but int is expected, hence the error. But in the “try foo5 with” case also, isn’t the expression of type unit but an alpha type is expected? Is the compiler not complaining because the return type of foo is generic? Could anyone please clarify?
The difference is that in the second case you have manually annotated the return type of fibonacci to be int, which keeps the typechecker from assigning a polymorphic type to it.
Oh ok. So if I had not annotated it, Fibonacci would also have the inferred type int → ‘a, right? Why is it inferring a generic return type in both the foo case and the Fibonacci case even though the print_endline’s return type is a unit type? Is it because in both the cases, an exception is raised and caught?
In an expression try e1 with exn -> e2 the types of e1 and e2 have to match, and the most general type that makes it so is assigned to the the whole try ... with ... expression. In your case, e1 (= foo 5 or fibonacci 10) would have type 'a (polymorphic), but e2 (= print_endline "...") has type unit, so the most general type that can be assigned to both 'a and unit is indeed unit, which becomes the type of the whole try ... with ... expression.