太急于推断ocaml可选函数参数

cou*_*ech 3 ocaml

考虑以下代码:

let myFun
  ?(f: ('a -> int) = (fun x -> x))
  (x: 'a)
    : int =
  f x
Run Code Online (Sandbox Code Playgroud)

看起来我不能用另一个参数调用int.当我尝试使用此代码时:

let usage = myFun ~f:String.length "abcdef"
Run Code Online (Sandbox Code Playgroud)

Ocaml发出以下错误消息:

Error: This expression has type string -> int
       but an expression was expected of type int -> int
       Type string is not compatible with type int 
Run Code Online (Sandbox Code Playgroud)

看起来推理会'a = int因为默认参数而思考.这是语言的限制,还是有一种方法来编写它以便编译?

ivg*_*ivg 5

符号?(f: ('a -> int)并不意味着参数f具有类型'a -> int,它是一个告诉类型推断算法的类型约束,它f应该是一个返回类型值的函数int.在'a这里只是意味着- "我不在乎,自己推断它".它不会推广您的类型变量.因此,给定您的约束,编译器推断,(1)fis 的类型int -> int(因为这是唯一满足您的默认值的输入),(2)类型x也是int,因为您自己约束它(它将是无论如何推断为相同类型,因为类型f.

此外,这里的类型系统是正确的,通过禁止除参数之外int的任何东西x.请考虑以下示例:

myFun "hello"
Run Code Online (Sandbox Code Playgroud)

根据你的愿望,它应该是有效的,但在这种情况下OCaml应该做什么?


oct*_*ron 5

由于如何实现optionals参数,此问题是一个限制.

实质上,使用标准选项类型在类型检查阶段扩展带有可选参数的函数.例如,你的功能:

let f ?(conv=(fun x -> x)) x = f x
Run Code Online (Sandbox Code Playgroud)

变得或多或少,

let f opt_conv =
let conv =
  match opt_conv with
  | None -> fun x -> x
  | Some f -> f in
 fun x -> conv x
Run Code Online (Sandbox Code Playgroud)

因此,由于opt_conv有型'a->'aNone分支,F必须有类型?conv:('a->'a) -> 'a -> 'a.

查看扩展函数,问题来自于Some分支和None应该具有不同类型以获得所需功能的事实.

对于类型谜语,在模式匹配的不同分支中具有不同类型是GADT可能带来潜在解决方案的标志:可以将扩展选项类型定义为

type ('default,'generic) optional =
  | Default: ('default,'default) optional
  | Custom: 'a -> ('default,'a) optional
Run Code Online (Sandbox Code Playgroud)

然后可以将您的函数重写为

let f: type a. (int -> int, a -> int) optional -> a -> int =
fun conv x ->
  match conv with
  | Default -> x
  | Custom f -> f x
Run Code Online (Sandbox Code Playgroud)

导致预期的行为:

f Default "hi"产生类型错误,而f (Custom int_of_string) "2"返回2.

但是,如果没有可选的参数语法糖机制,这并不是真的有用.

没有人可以完全扩展OCaml以使用GADT-laded optional类型.然而,这很容易导致类型错误,并且相应的复杂性增加不会产生非常有吸引力的扩展.