如何强制 OCaml 推断更通用的类型?

how to force OCaml to infer a more general type?

我想定义一个接受可选参数的函数,该参数是一个函数 ('a -> 'b)。默认值应该是标识,实际上是 ('a -> 'a),但我看不出为什么它不应该与更通用的 ('a -> 'b) 兼容。当我尝试时:

let optional_apply ?f i =
    match f with 
    | None -> i + 4
    | Some fn -> fn (i + 4)

我总是得到窄型 ?f:(int -> int) -> int -> int。但我想将 f 保持为 int -> 'b。我能做些什么?或者这只是不合理的,因为 optional_apply 没有确定的类型?如果是这样,我将如何获得类似的功能?

这与通用类型不兼容('a -> 'b)原因如下:

  • 第一个模式 None -> i + 4int 类型,因此将函数的 return 类型限制为 int.

  • 第二个模式 Some fn -> fn (i + 4) 必须 int 类型。因为 (i + 4) 也是 int 类型,fn 也必须采用 return 和 int,因此 int -> int.


我能想到的最佳选择是 Haskell 的 maybe 函数,类型为 ('a -> 'b) -> 'b -> 'a option -> 'b:

let maybe fn backup opt = match opt with
    | Some v -> fn v
    | None   -> backup
;;

...您可能可以根据自己的用例进行调整。

不可能,f参数一定不能是可选的。一个简单的解释是,可选参数只是一个语法糖。 因此,如果没有糖,您的函数可以重写为以下形式:

let optional_apply f n = match f with
  | Some f -> f (n + 4)
  | None -> (n + 4)

这里的类型检查器只允许我们为 f 使用一种类型:int -> int。如果它允许我们使用 int -> 'a 类型,那么表达式的 None 路径将是不可靠的。换句话说,根据 fNone 还是 Someoptional_apply 将评估为不同的类型。这被认为是不合理的。

证明不健全的最好方法是举一个简单的例子,typechecker 将允许不健全的程序:

let f = ref None
let g n = optional_apply ?f:!f n

有了这个定义,如果类型检查器允许 f 参数保持多态性,那么我们可以随时 "break" g 通过改变 f 对任何东西的引用来发挥作用别的。