ocaml 多态变体类型推断类型过于笼统
ocaml polymorphic variant type inferred type too general
我有这个代码
let my_fun: [`X | `Y | `Z] -> [`Z | `Y] = function
| `X -> `Y
| x -> x
它不会编译消息
11 | | x -> x
^
Error: This expression has type [ `X | `Y | `Z ]
but an expression was expected of type [ `Y | `Z ]
The second variant type does not allow tag(s) `X
为什么 complire 不能推断类型 [<code>Z |
Y] 如果很明显 `X 永远不会从函数返回?
如果 x
的类型被推断为 [`Y | `Z]
,那么它不能用于 [`X | `Y | `Z]
类型,这很奇怪,因为它绑定到一个参数那种。
您可以使用 as
模式来获得具有精炼类型的绑定,如下所示:
let my_fun: [`X | `Y | `Z] -> [`Y | `Z] = function
| `X -> `Y
| (`Y | `Z) as yz -> yz
如果您想对许多情况下的多态变体执行此操作,#type_name
模式会非常有用。
Why can't the compiler infer the type [Z |Y] if it is clear that `X can be never returned from the function?
一个更简单的例子是:
if false then 0 else "hello"
编译器必须拒绝它,因为在 ML 语言中键入要求两个分支具有相同的类型 1,并且类型 int
和string
不能统一;这是真的,即使你可以说表达式永远不可能计算为 0(请记住,从形式上讲,说我们计算一个不属于所定义语言的表达式是没有意义的)。
在match
表达式中,所有子句左边部分的类型必须统一为被匹配表达式的类型。所以最后一个子句中的 x
与 function
中的隐式参数具有相同的类型,这是签名中声明的输入类型。无论 `X
在该上下文中是否为有效值,都是如此。
你需要列举出所有有效的情况;如果您在代码中经常需要它,那么您最好为此编写一个专用函数:
let f : ([> `Y | `Z ] -> [`Y | `Z ] option) = function
| (`Y|`Z) as u -> (Some u)
| _ -> None;
例如:
# f `O;;
- : [ `Y | `Z ] option = None
# f `Y;;
- : [ `Y | `Z ] option = Some `Y
另见 Set-Theoretic Types for Polymorphic Variants (pdf)
[1] 为了比较,在动态类型的Common Lisp中,等效表达式是有效的; SBCL 编译器完成的静态分析可以推断其类型,即长度为 5 的字符串:
> (describe (lambda () (if nil 0 "hello")))
....
Derived type: (FUNCTION NIL
(VALUES (SIMPLE-ARRAY CHARACTER (5)) &OPTIONAL))
我有这个代码
let my_fun: [`X | `Y | `Z] -> [`Z | `Y] = function
| `X -> `Y
| x -> x
它不会编译消息
11 | | x -> x
^
Error: This expression has type [ `X | `Y | `Z ]
but an expression was expected of type [ `Y | `Z ]
The second variant type does not allow tag(s) `X
为什么 complire 不能推断类型 [<code>Z |
Y] 如果很明显 `X 永远不会从函数返回?
如果 x
的类型被推断为 [`Y | `Z]
,那么它不能用于 [`X | `Y | `Z]
类型,这很奇怪,因为它绑定到一个参数那种。
您可以使用 as
模式来获得具有精炼类型的绑定,如下所示:
let my_fun: [`X | `Y | `Z] -> [`Y | `Z] = function
| `X -> `Y
| (`Y | `Z) as yz -> yz
如果您想对许多情况下的多态变体执行此操作,#type_name
模式会非常有用。
Why can't the compiler infer the type [Z |Y] if it is clear that `X can be never returned from the function?
一个更简单的例子是:
if false then 0 else "hello"
编译器必须拒绝它,因为在 ML 语言中键入要求两个分支具有相同的类型 1,并且类型 int
和string
不能统一;这是真的,即使你可以说表达式永远不可能计算为 0(请记住,从形式上讲,说我们计算一个不属于所定义语言的表达式是没有意义的)。
在match
表达式中,所有子句左边部分的类型必须统一为被匹配表达式的类型。所以最后一个子句中的 x
与 function
中的隐式参数具有相同的类型,这是签名中声明的输入类型。无论 `X
在该上下文中是否为有效值,都是如此。
你需要列举出所有有效的情况;如果您在代码中经常需要它,那么您最好为此编写一个专用函数:
let f : ([> `Y | `Z ] -> [`Y | `Z ] option) = function
| (`Y|`Z) as u -> (Some u)
| _ -> None;
例如:
# f `O;;
- : [ `Y | `Z ] option = None
# f `Y;;
- : [ `Y | `Z ] option = Some `Y
另见 Set-Theoretic Types for Polymorphic Variants (pdf)
[1] 为了比较,在动态类型的Common Lisp中,等效表达式是有效的; SBCL 编译器完成的静态分析可以推断其类型,即长度为 5 的字符串:
> (describe (lambda () (if nil 0 "hello")))
....
Derived type: (FUNCTION NIL
(VALUES (SIMPLE-ARRAY CHARACTER (5)) &OPTIONAL))