为什么类型推断算法会因为 'Fun.flip Option.bind' 而混淆?
Why type inference algorithm confuses because of 'Fun.flip Option.bind'?
模块中函数声明的共同特征是最后一个参数具有主状态类型 (Module.t)。就像在 'List' 模块中一样。此表单打开了使用“|>”运算符的能力,例如:
[1;2;3] |> List.filter ((>)2)
|> List.map ((-)1)
|> List.fold_left 0 (+)
但是 'Option' 模块中的函数 'bind' 不遵循这种形式。它有 '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
^
Error: This expression has type a -> b option but an expression was expected of > type int -> a option. Type a is not compatible with type 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
的定义不够多态。因为你把它定义为一个应用程序(Fun.flip到Option.bind),由于值的限制,它不能被做成多态的。
如果你这样定义它:
let opt_bind a b = Fun.flip Option.bind a b
或者,等价地,像这样:
let opt_bind a b = Option.bind b a
那么事情就会成功。
如果您询问 opt_bind
定义的类型,您将看到问题:
# let opt_bind = Fun.flip Option.bind;;
val opt_bind :
('_weak3 -> '_weak4 option) -> '_weak3 option ->
'_weak4 option = <fun>
"weak" 类型变量告诉您生成的函数不是多态的。
本质区别在于Fun.flip Option.bind
在语法上是一个应用程序(一个函数调用)。这样的表达式不能成为多态的。两种替代形式将 bind_opt
定义为 lambda(函数值),在值限制的术语中是句法 "value"。
需要值限制以确保多态函数是可靠的(即,它们不允许对值进行不适当的操作)。
我选择的值限制参考(尤其是在 OCaml 中实现的)是这篇论文:Relaxing the Value Restriction, Jacques Garrigue
模块中函数声明的共同特征是最后一个参数具有主状态类型 (Module.t)。就像在 'List' 模块中一样。此表单打开了使用“|>”运算符的能力,例如:
[1;2;3] |> List.filter ((>)2)
|> List.map ((-)1)
|> List.fold_left 0 (+)
但是 'Option' 模块中的函数 'bind' 不遵循这种形式。它有 '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 ^
Error: This expression has type a -> b option but an expression was expected of > type int -> a option. Type a is not compatible with type 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
的定义不够多态。因为你把它定义为一个应用程序(Fun.flip到Option.bind),由于值的限制,它不能被做成多态的。
如果你这样定义它:
let opt_bind a b = Fun.flip Option.bind a b
或者,等价地,像这样:
let opt_bind a b = Option.bind b a
那么事情就会成功。
如果您询问 opt_bind
定义的类型,您将看到问题:
# let opt_bind = Fun.flip Option.bind;;
val opt_bind :
('_weak3 -> '_weak4 option) -> '_weak3 option ->
'_weak4 option = <fun>
"weak" 类型变量告诉您生成的函数不是多态的。
本质区别在于Fun.flip Option.bind
在语法上是一个应用程序(一个函数调用)。这样的表达式不能成为多态的。两种替代形式将 bind_opt
定义为 lambda(函数值),在值限制的术语中是句法 "value"。
需要值限制以确保多态函数是可靠的(即,它们不允许对值进行不适当的操作)。
我选择的值限制参考(尤其是在 OCaml 中实现的)是这篇论文:Relaxing the Value Restriction, Jacques Garrigue