首页 > 解决方案 > 带标签的参数

问题描述

考虑以下顶级会话,它定义了一个带有标签参数的函数f,但在调用它时不使用标签:

# 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

这工作正常。但是,如果我尝试对JaneStreet 的 Hashtbl 模块中的函数做同样的事情:

# 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*)

t在说出以下内容时,我会遇到类型错误-

错误:此表达式的类型为 ('a, int) Core.String.Table.t_ = (Core.String.Table.key, int) Base.Hashtbl.t 但表达式应为 ('b, 'c - > 'd) Core.String.Table.t_ = (Core.String.Table.key, 'c -> 'd) Base.Hashtbl.t 类型 int 与类型 'c -> 'd 不兼容

我无法破译为什么这不进行类型检查。如果有人能解释一下为什么前者有效而后者无效,我将不胜感激。

标签: typesocaml

解决方案


不同之处在于您的示例具有具体的返回类型,find_or_add而是多态的。它的类型签名是:

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

由于 currying 和 because'b 可以是一个函数,带有省略标签的参数将被推断为属于​​返回的函数,这就是为什么错误消息说“一个表达式应该是类型 ('b, 'c -> 'd) Core.String.Table.t”。只有当一个应用程序是全部时,标签才能被省略,在这种情况下它不是。

我相信你可以通过添加一个类型注释来解决这个问题,t但是从那时起返回类型将是具体的并且应用程序总数:

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

推荐阅读