Question

I am trying to write a function that just raises an exception. It works, but I cannot use it within another function when the argument is labeled.

Here is a simple example:

let raise_error ~m = failwith m

let test = function
  | true -> raise_error "ok"
  | false -> raise_error "ko"

There is a warning, and the function does not have the type I expected:

Warning 20: this argument will not be used by the function.
Warning 20: this argument will not be used by the function.
val test : bool -> m:string -> 'a = <fun>

This other function fails to compile:

let test2 = function
  | true -> "ok"
  | false -> raise_error "ko"

with the message:

Warning 20: this argument will not be used by the function.
Error: This expression has type m:string -> 'a
but an expression was expected of type string

I don't understand what's wrong, because it works if the argument is not labeled.

Is there a way to get around this?

Was it helpful?

Solution

You could label the arguments at the call sites:

let raise_error ~m = failwith m

let test = function
  | true -> raise_error ~m:"ok"
  | false -> raise_error ~m:"ko"

let test2 = function
  | true -> "ok"
  | false -> raise_error ~m:"ko"

A better solution is to rewrite raise_error to not use labelled arguments.

The issue is that raise_error as written has a type of m:string -> 'a, so you can pass it any number of non-labelled arguments and the resulting expression will still be a function of type m:string -> 'a. This is error prone and surprising, so you should avoid using labelled arguments with diverging functions.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top