考虑以下代码:
let myFun
?(f: ('a -> int) = (fun x -> x))
(x: 'a)
: int =
f x
看起来我无法使用int
以外的其他参数调用。当我尝试使用此代码时:
let usage = myFun ~f:String.length "abcdef"
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
由于默认参数,推理看起来会认为是'a = int
。这是语言的限制,还是有一种方法可以编写它以便编译?
答案 0 :(得分:5)
由于如何实施optionals参数,此问题是一个限制。
基本上,使用标准选项类型在类型检查阶段扩展带有可选参数的函数。例如,你的功能:
let f ?(conv=(fun x -> x)) x = f x
或多或少地变得
let f opt_conv =
let conv =
match opt_conv with
| None -> fun x -> x
| Some f -> f in
fun x -> conv x
因此,由于opt_conv
对'a->'a
分支中的None
类型有效,因此f必须为?conv:('a->'a) -> 'a -> 'a
类型。
查看扩展函数,问题来自Some
分支和None
应具有不同类型以获得所需功能的事实。
为了类型谜语,在模式匹配的不同分支中具有不同类型是GADT可能带来潜在解决方案的标志:可以将扩展选项类型定义为
type ('default,'generic) optional =
| Default: ('default,'default) optional
| Custom: 'a -> ('default,'a) optional
然后可以将您的功能重写为
let f: type a. (int -> int, a -> int) optional -> a -> int =
fun conv x ->
match conv with
| Default -> x
| Custom f -> f x
导致预期的行为:
f Default "hi"
会产生类型错误,而f (Custom int_of_string) "2"
会返回2.
但是,如果没有可选的参数语法糖机制,这实际上并没有用。
无论如何完全可以扩展OCaml以使用GADT-laded optional
类型。然而,这很容易导致类型错误,相应的复杂性增加并不会带来非常有吸引力的扩展。