I want to define a function that accepts an optional argument which is a function ('a -> 'b). The default value should be the identity, which is actually ('a -> 'a)
, but i see no reason why it should not be compatible with the more general ('a -> 'b)
. When i try:
let optional_apply ?f i =
match f with
| None -> i + 4
| Some fn -> fn (i + 4)
I always get the narrow type ?f:(int -> int) -> int -> int
. But I want to keep f as int -> 'b
. What can i do? Or is this just unsound, since optional_apply
would not have a definite type? If so, how would I get a similar functionality?
It is impossible, the f
argument must not be optional. A simple explanation, is that optional parameters are just a syntactic sugar.
So without sugar your function can be rewritten in a following form:
let optional_apply f n = match f with
| Some f -> f (n + 4)
| None -> (n + 4)
And here typechecker allows us only one type for f
: int -> int
. If it allowed us an int -> 'a
type, then the None
path of expression would be unsound. In other words, depending on whether f
is None
or Some
the optional_apply
will evaluate to different types. And this is considered unsound.
The best way to prove the unsoundness is to give a simple example where typechecker will allow unsound program:
let f = ref None
let g n = optional_apply ?f:!f n
with this definitions, if type checker allowed f
parameter to remain polymorphic, then we can at any time "break" g
function by changing f
reference to anything else.
This is not compatible with the general type ('a -> 'b)
. Here's why:
The first pattern, None -> i + 4
is of type int
, thus restricting the function's return type to int
.
The second pattern, Some fn -> fn (i + 4)
must then also be of type int
. Because (i + 4)
is of type int
, too, fn
must take and return an int
, thus int -> int
.
The best alternative I can think of is Haskell's maybe
function, of type ('a -> 'b) -> 'b -> 'a option -> 'b
:
let maybe fn backup opt = match opt with
| Some v -> fn v
| None -> backup
;;
... which you can probably adapt to your use case.