ocaml - 为什么类型推断算法会因为“Fun.flip Option.bind”而混淆?
问题描述
模块中函数声明的常见签名是最后一个参数具有主状态(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'不是通用的?
如何使用带有“|>”符号的“绑定”?
解决方案
你的问题是你的定义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(函数值),它是值限制术语中的句法“值”。
需要值限制以确保多态函数是合理的(即,它们不允许对值进行不适当的操作)。
我选择的值限制参考(尤其是在 OCaml 中实现的)是这篇论文:Relaxing the Value Restriction, Jacques Garrigue
推荐阅读
- xero-api - 我可以将 Stitch 与多个 Xero 帐户一起使用吗?
- mysql - 仅当记录列匹配三个条件时才显示 DISTINCT user_id
- javascript - 使用节点 JS 读取 pdf 文件
- sql - 仅检索我在另一个表中没有的用户
- c# - 如何在 ListView Visual Studio 中加载对象类型数据
- html - Safari 嵌套 flex 问题
- apache-nifi - 通过动态名称访问参数
- ios - 每次 Apple 发布新的 XCode 版本时,我的 UI 测试都会失败
- elasticsearch - 如何使用 NEST 构造记录的聚合(计数)?
- c++ - 在 C++ 中将数组打印为表格