Named arguments signature order


I seem to have trouble understanding the semantics of named arguments. I thought that applying any named argument will take the argument from anywhere in the signature and eliminate it.


let full ~foo:_ ~bar:_ () = 1


(full ~bar:1);;
- : foo:'a -> unit -> int = <fun>

So far so good.

I have this code which tries to partially apply full but while

let curried f = f ~foo:1

let _ = (curried full) ~bar:2 ()

works, flipping the order

let curried f = f ~bar:1

let _ = (curried full) ~foo:2 ()

fails with

Error: This expression has type foo:'a -> bar:'b -> unit -> int
       but an expression was expected of type bar:int -> 'c

Thus my intuition that the order does not matter is not quite true. Can someone tell me where my intuition mislead me? For a moment I was excited that named arguments would allow partial application of any argument in any order.

The short answer is that the order of arguments does matter in general and it is only in multi-application (e.g f ~x:0 ~y:1) that the compiler permutes the arguments to match the argument order in the application with the order specified by the function type.

One way to understand this behavior is that labeled multi-applications are translated to normal applications after type checking, thus in a application like f ~x:0 ~y:1, the typechecker must decide locally the mapping between label names and argument position.