函数f
参数类型是[< 'A | 'B]
,这就是我想要的。
# let rec f = function
| `A -> 0
| `B -> let _ = f in 1
;;
val f : [< `A | `B ] -> int = <fun>
但是,如果我使用'A
以递归方式调用它,则会向我推断出不需要的[< 'A | 'B > 'A]
类型,至少需要'A
:
# let rec f = function
| `A -> 0
| `B -> let _ = f `A in 1
;;
val f : [< `A | `B > `A ] -> int = <fun>
我仍需要递归调用f 'A
,但如何保留[< 'A | 'B]
类型?
答案 0 :(得分:2)
这是let
- 多态约束的另一个实例,它阻碍了多态递归函数的使用。因为,OCaml 3.12我们有一个explicit way来声明你的函数是多态的。
你的情况有点复杂,因为你有隐式类型变量,它发生在row-polymorphic类型中。也许有更好的方法,但我的方法是使这个类型变量显式化,具有以下类型定义
type 'a t = 'a constraint 'a = [< `A | `B]
使用这种方便的类型,很容易为函数编写适当的注释:
let rec f : 'a . 'a t -> int = function
| `A -> 0
| `B -> let _ = f `A in 1
以防万一,如果您不想公开此'a t
,那没关系,因为您不需要,'a t
等于{{ 1}}它只是使[< 'A | 'B]
类型变量显式:
'a
如果不引入module M : sig
val f : [< `A | `B] -> int
end = struct
let rec f : 'a . 'a t -> int = function
| `A -> 0
| `B -> let _ = f `A in 1
end;;
类型,你可以稍微用一点(但这当然是品味的话)来表示:
'a t
当然,对于非平凡的类型,这不会扩展。