Reputation: 177
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
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