Ocaml 为什么类型推断算法会因为“Fun.flip Option.bind”而混淆?
模块中函数声明的常见签名是当最后一个参数的类型为main state module.t时。就像在“列表”模块中一样。此表单打开了使用“|>”运算符的功能,如: [1;2;3]|>List.filter>2 |>List.map-1 |>List.fold_左0+ 但“Option”模块中的函数“bind”不遵循此形式。它的第一个参数是'Option.t' val bind:'a option->'a->'b option->'b option 但是好的,我可以改变它。我用参数的相反顺序声明了函数“opt_bind” 让opt_bind=Fun.flip Option.bind 但是这个不行。下面的代码是用下面的错误编译的 a型=整数的a型 类型b=int的类型b 设fx=A x 设g A x=某个B x 让opt_bind=Fun.flip Option.bind 让结果= 一些42 |>opt|u绑定f |>选择绑定 错误:此表达式具有类型a->b选项,但表达式应为>类型int->a选项。类型a与类型int不兼容 同样的情况 让结果= 设x=opt_绑定f约42 in 设x=opt_绑定gx-in x 即使在我注意到所有类型之后,我仍然有同样的问题 让f:int->a option=funx->Some a x 让g:a->b option=fun a x->Some b x 让opt_绑定:'a->'b option->'a option->'b option= Fun.flip Option.bind 让结果:b选项= 设x:a option=opt_绑定f约42 in 设x:b option=opt_绑定gx in x;; 但是 让结果= 设x=Option.bind约42 f in 设x=Option.bind x g in x 很好 为什么“opt_bind”对“g”有错误的类型期望,好像“opt_bind”不是泛型的?Ocaml 为什么类型推断算法会因为“Fun.flip Option.bind”而混淆?,ocaml,type-inference,value-restriction,Ocaml,Type Inference,Value Restriction,模块中函数声明的常见签名是当最后一个参数的类型为main state module.t时。就像在“列表”模块中一样。此表单打开了使用“|>”运算符的功能,如: [1;2;3]|>List.filter>2 |>List.map-1 |>List.fold_左0+ 但“Option”模块中的函数“bind”不遵循此形式。它的第一个参数是'Option.t' val bind:'a option->'a->'b option->'b option 但是好的,我可以改变它。我用参数的相反顺序声明了函数
如何将“bind”与“|>”符号一起使用?您的问题是您对opt|u bind的定义不够多态。由于您将其定义为Fun.flip to Option.bind的应用程序,因此由于值限制,无法使其具有多态性 如果您这样定义它:
let opt_bind a b = Fun.flip Option.bind a b
let opt_bind a b = Option.bind b a
或者,等价地,像这样:
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 a函数值,这是值限制术语中的语法值
值限制是为了确保多态函数是可靠的,即它们不允许对值进行不适当的操作
我选择在OCaml中实现的值限制的参考是本文:您的问题是您对opt_bind的定义不够多态。由于您将其定义为Fun.flip to Option.bind的应用程序,因此由于值限制,无法使其具有多态性 如果您这样定义它:
let opt_bind a b = Fun.flip Option.bind a b
let opt_bind a b = Option.bind b a
或者,等价地,像这样:
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 a函数值,这是值限制术语中的语法值
值限制是为了确保多态函数是可靠的,即它们不允许对值进行不适当的操作
对于值限制,特别是在OCaml中实现的值限制,我选择的参考是本文:类型注释不能绕过值限制。它们并不意味着你在这种情况下的想法——opt_-bind仍然不是多态的;相反,“a”和“b”用弱类型变量统一起来。注释中类型变量的这种误导性语义可以说是OCaml的一个缺陷。您需要使用至少一个参数来扩展定义,而不是注释,如Jeffrey的答案所示。这避免了值限制。另请参见,类型批注无法绕过值限制。它们并不意味着你在这种情况下的想法——opt_-bind仍然不是多态的;相反,“a”和“b”用弱类型变量统一起来。注释中类型变量的这种误导性语义可以说是OCaml的一个缺陷。您需要使用至少一个参数来扩展定义,而不是注释,如Jeffrey的答案所示。这避免了值限制。另请参见,