为什么类型推理算法因为"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
^                     

错误:此表达式具有类型a->b选项,但应为>类型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的定义不够多态。因为你将它定义为一个应用程序(从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>

"弱"类型变量告诉您生成的函数不是多态的。

本质区别在于Fun.flip Option.bind在语法上是一个应用程序(一个函数调用(。这样的表达不可能是多态的。这两种替代形式将bind_opt定义为lambda(函数值(,在值限制的术语中,lambda是语法上的"值"。

需要值限制来确保多态函数是健全的(即,它们不允许对值进行不适当的操作(。

我选择值限制(尤其是在OCaml中实现的值限制(的参考是本文:放松值限制,Jacques Garrigue

相关内容

  • 没有找到相关文章

最新更新