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

如何强制OCaml推断更一般的类型?,ocaml,Ocaml,我想定义一个接受可选参数的函数,该参数是一个函数('a->'b)。默认值应该是identity,它实际上是('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。我能

我想定义一个接受可选参数的函数,该参数是一个函数('a->'b)。默认值应该是identity,它实际上是
('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\u apply
没有明确的类型?如果是这样,我如何获得类似的功能?

这与常规类型
('a->'b)
不兼容,原因如下:

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

  • 第二种模式,
    somefn->fn(i+4)
    也必须是
    int
    类型。因为
    (i+4)
    也是
    int
    类型,
    fn
    必须获取并返回
    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)
在这里,typechecker只允许我们为
f
使用一种类型:
int->int
。如果它允许我们使用
int->'a
类型,那么
None
表达式的路径将是不健全的。换句话说,根据
f
None
还是
Some
的不同,
可选应用将对不同类型进行评估。这被认为是不合理的

证明不健全的最佳方法是给出一个简单的示例,其中typechecker将允许不健全的程序:

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

使用此定义,如果类型检查器允许
f
参数保持多态性,那么我们可以随时通过更改
f
引用来“中断”
g
函数

我同意你的解释。很难理解为什么会这样。使用非可选参数
f
而不是
?f
,函数只是一个普通的
apply
,保持
f
的类型为常规类型没有问题
apply
是多态的,可以与不同类型的
f
一起重复使用,没有问题。好的,因此考虑可选参数的方法是定义函数时固定的
option
类型。我错误地想象了一个类似于懒惰的打字构造的东西,它在需要时才被发现。但在Ocaml的背景下,这可能是胡说八道。