如何强制OCaml推断更一般的类型?

时间:2015-02-01 20:52:36

标签: ocaml

我想定义一个接受可选参数的函数,该函数是一个函数(' 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不会有明确的类型?如果是这样,我将如何获得类似的功能?

2 个答案:

答案 0 :(得分:3)

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

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

在这里,typechecker只允许我们使用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引用更改为其他任何内容来发挥作用。

答案 1 :(得分:2)

这与一般类型('a -> 'b)不兼容。这就是原因:

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

  • 第二种模式Some fn -> fn (i + 4)必须属于int类型。由于(i + 4)类型为intfn必须接受并返回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
;;

...你可以适应你的用例。