Too eager infering of ocaml optional function argument

ocaml

Solution

This issue is a limitation due to how optionals argument are implemented.

Essentially, function with optional argument are expanded during the type checking phase using the standard option type. For instance, your function:

let f ?(conv=(fun x -> x)) x = f x

becomes, more or less,

let f opt_conv =
let conv =
  match opt_conv with
  | None -> fun x -> x
  | Some f -> f in
 fun x -> conv x

Consequently, since the `opt_conv` has for type `'a->'a` in the `None` branch, f must have for type `?conv:('a->'a) -> 'a -> 'a` .

Looking at the expanded function, the problem comes from the fact that the `Some` branch and `None` should have different type to obtain your desired functionality.

For the sake of type riddles, having different types in different branch of a pattern matching is a sign that GADTs may bring a potential solution: one can define an extended option type as

type ('default,'generic) optional =
  | Default: ('default,'default) optional
  | Custom: 'a -> ('default,'a) optional

then it is possible to rewrite your function as

let f: type a. (int -> int, a -> int) optional -> a -> int =
fun conv x ->
  match conv with
  | Default -> x
  | Custom f -> f x

wich leads to the expected behavior:

`f Default "hi"` yields a type error whereas `f (Custom int_of_string) "2"` returns 2.

However, without the optional argument syntactic sugar machinery, this is not really useful.

None that it is perfectly possible to extend OCaml to use the GADT-laded `optional` type. However this can easily lead to atrocious type errors and the corresponding increase of complexity does not make for a very attractive extension.

Problem

Consider this code: ``` let myFun ?(f: ('a -> int) = (fun x -> x)) (x: 'a) : int = f x ``` Looks i can't call with another argument other than `int`. When I try to with this code: ``` let usage = myFun ~f:String.length "abcdef" ``` Ocaml emits this error message: ``` Error: This expression has type string -> int but an expression was expected of type int -> int Type string is not compatible with type int ``` Looks like the inference will think `'a = int` because of the default argument. It is the limitation of the language or is there a way how to write this so it compiles?

Original source