【发布时间】:2020-08-23 10:58:52
【问题描述】:
模块中函数声明的常见签名是最后一个参数的类型是主状态 (Module.t)。就像在“列表”模块中一样。此表单打开了使用“|>”运算符的能力,例如:
[1;2;3] |> List.filter ((>)2)
|> List.map ((-)1)
|> List.fold_left 0 (+)
但“选项”模块中的“绑定”函数不遵循这种形式。它有'Option.t'参数作为第一个
val bind : 'a option -> ('a -> 'b option) -> 'b option
但是好的,我可以改变它。我用相反的参数顺序声明了函数'opt_bind'。
let opt_bind = Fun.flip Option.bind
但是这个不行。并且下面的代码编译时出现如下错误
type a = A of int
type b = B of int
let f x = Some (A x)
let g (A x) = Some (B x)
let opt_bind = Fun.flip Option.bind
let result =
(Some 42) |> opt_bind f
|> opt_bind g
|> opt_bind g ^错误:此表达式具有类型 a -> b 选项,但表达式应为 > type int -> a 选项。 a 类型与 int 类型不兼容
同样的情况
let result =
let x = opt_bind f (Some 42) in
let x = opt_bind g x in
x
即使在我注意到所有类型之后,我仍然遇到同样的问题。
let f : int -> a option = fun x -> Some (A x)
let g : a -> b option = fun (A x) -> Some (B x)
let opt_bind : ('a -> 'b option) -> 'a option -> 'b option =
Fun.flip Option.bind
let result : b option =
let x : a option = opt_bind f (Some 42) in
let x : b option = opt_bind g x in
x ;;
但是
let result =
let x = Option.bind (Some 42) f in
let x = Option.bind x g in
x
工作正常。
为什么“opt_bind”对“g”有错误的类型期望,好像“opt_bind”不是通用的?
如何使用带有 '|>' 符号的 'bind'?
【问题讨论】:
-
类型注解不能绕过值限制。在这种情况下,它们并不代表您的想法——
opt_bind仍然不是多态的;相反,'a和'b与弱类型变量统一。 (注释中类型变量的这种误导性语义可以说是 OCaml 的错误特征。)您需要使用至少一个参数“扩展”定义而不是注释,如 Jeffrey 的回答所示。这避免了价值限制。
标签: ocaml type-inference value-restriction