Author: Christian.Queinnec@lip6.fr

## Polymorphism and return values of functions

Objective CAML's parametric polymorphism permits the definition of functions whose return type is completely unspecified. For example:

    # let id x = x ;;
    val id : 'a -> 'a = <fun>

However, the return type depends on the type of the argument. Thus, when the function `id` is applied to an argument, the type inference mechanism knows how to instantiate the type variable 'a. So for each particular use, the type of `id` can be determined.
If this were not so, it would no longer make sense to use strong static typing, entrusted with ensuring execution safety. Indeed, a function of completely unspecified type such as 'a -> 'b would allow any type conversion whatsoever, which would inevitably lead to a run-time error since the physical representations of values of different types are not the same.

#### Apparent contradiction

However, it is possible in the Objective CAML language to define a function whose return type contains a type variable which does not appear in the types of its arguments. We will consider several such examples and see why such a possibility is not contradictory to strong static typing.
Here is a first example:

    # let f x = [] ;;
    val f : 'a -> 'b list = <fun>

This function lets us construct a polymorphic value from anything at all:

    # f () ;;
    - : '_a list = []
    # f "anything at all" ;;
    - : '_a list = []

Nevertheless, the value obtained isn't entirely unspecified: we're dealing with a list. So it can't be used just anywhere.
Here are three examples whose type is the dreaded 'a -> 'b:

    # let rec f1 x = f1 x ;;
    val f1 : 'a -> 'b = <fun>
    # let f2 x = failwith "anything at all" ;;
    val f2 : 'a -> 'b = <fun>
    # let f3 x = List.hd [] ;;
    val f3 : 'a -> 'b = <fun>

These functions are not, in fact, dangerous vis-a-vis execution safety, since it isn't possible to use them to construct a value: the first one loops forever, the latter two raise an exception which interrupts the computation.
Similarly, it is in order to prevent functions of type 'a -> 'b from being defined that new exception constructors are forbidden from having arguments whose type contains a variable.
Indeed, if one could declare a polymorphic exception `Poly_exn` of type 'a -> exn, one could then write the function:

    let f = function
       0 -> raise (Poly_exn false)
     | n -> n+1 ;;

The function `f` being of type int -> int and `Poly_exn` being of type 'a -> exn, one could then define:

    let g n = try f n with Poly_exn x -> x+1 ;;

This function is equally well-typed (since the argument of `Poly_exn` may be arbitrary) and now, evaluation of `(g 0)` would end up in an attempt to add an integer and a boolean!