Rahul
Rahul

Reputation: 177

Labelled Arguments

Consider the following top-level session that defines a function with a labelled argument f, but does not use the label while calling it:

# let dummy x y ~f:f = x-y+(f());;
val dummy : int -> int -> f:(unt -> int) -> int = <fun>

# dummy 2 3 (fun () -> 5);;
- : int = 4

This works fine. However, if I try to do the same with a function in JaneStreet's Hashtbl module as such :

# open Core.String;;

# let t = Table.create();;
val t : ('a, '_weak1) Core.String.Table.t_ = <abstr>

# Table.find_or_add t "a" ~default:(fun () -> 5);; (*This works fine*)
- : int = 5

# Table.find_or_add t "b" (fun () -> 1);; (*This does not typecheck*)

I get thrown a type error on t saying the following -

Error: This expression has type ('a, int) Core.String.Table.t_ = (Core.String.Table.key, int) Base.Hashtbl.t but an expression was expected of type ('b, 'c -> 'd) Core.String.Table.t_ = (Core.String.Table.key, 'c -> 'd) Base.Hashtbl.t Type int is not compatible with type 'c -> 'd

I am unable to decipher why this does not typecheck. If someone could kindly explain me why the former works but not the latter, I would greatly appreciate it.

Upvotes: 0

Views: 39

Answers (1)

glennsl
glennsl

Reputation: 29106

The difference is that your example has a concrete return type, while find_or_add is polymorphic. Its type signature is:

val find_or_add : ('a, 'b) t -> 'a key -> default:(unit -> 'b) -> 'b

Because of currying and because 'b can be a function, the argument with omitted label will be inferred to belong to the returned function, and is why the error message says "an expression was expected of type ('b, 'c -> 'd) Core.String.Table.t". Labels can only be omitted if an application is total, which in this case it's not.

I believe you can fix this just by adding a type annotation to t however, since then the return type will be concrete and the application total:

let t : (Table.key, int) Hashtbl.t = Table.create();;

Upvotes: 2

Related Questions