Ocaml 强制为具有更严格的默认值的可选参数使用更广泛的类型

Ocaml 强制为具有更严格的默认值的可选参数使用更广泛的类型,ocaml,Ocaml,有没有一种方法可以使可选参数f足够灵活,使类型'a->'b,但仍然默认为identity,因为identity具有类型'a->'a 首先陈述我的问题,确切地说: 我想定义一个函数,它接受一个可选参数 函数('a->'b)。默认值应为标识,该标识 实际上是('a->'a),但我看不出有什么理由不应该是 与更一般的('a->'b)兼容 然而,这个问题包含了一个例子,说明了一个更狭隘的问题。对那个问题的回答回答了一个更狭隘的问题。以下是对一般问题的简单说明: # let g1 ~f x = f x;;

有没有一种方法可以使可选参数
f
足够灵活,使类型
'a->'b
,但仍然默认为
identity
,因为
identity
具有类型
'a->'a

首先陈述我的问题,确切地说:

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

然而,这个问题包含了一个例子,说明了一个更狭隘的问题。对那个问题的回答回答了一个更狭隘的问题。以下是对一般问题的简单说明:

# let g1 ~f x = f x;;
val g1 : f:('a -> 'b) -> 'a -> 'b = <fun>
identity
上添加类型规范无助于:

# let g3 ?(f=(identity:'a -> 'b)) x = f x;;
val g3 : ?f:('b -> 'b) -> 'b -> 'b = <fun>
简单使用:

# let vs = Batteries.List.range 1 `To 100;;
# let ks = [4; 10];;
# select ks vs;;
- : int list = [4; 10]
更普遍的用法是当ks的元素是,比如,带有一个整数键字段的记录时。然后,
accessor
函数将从记录类型映射到
int


(是的,我知道使用
hd
tl
有点不寻常。它可以更好地转换为惰性列表上下文。)

我认为看待这一点的方法是想象您的函数将具有什么类型。您似乎想要这种类型:

?f:('a -> 'b) -> 'a -> 'b
但是,这并不能说明当您省略可选参数时,类型将恢复为
'a->'a

相反,这种类型的意思是,如果您省略了可选参数,那么您就拥有了类型为
'a->'b
的函数。但是没有格式良好的
'a->'b
类型的函数。这只能是永远不会返回(或类似)的函数类型


我的看法是,OCaml类型的系统不能表示您想要的功能,即使它确实有意义。

OCaml根本不支持这一点。不能使用根据是否传递了可选参数而优化的类型编写函数

与相关问题中的一些答案不同,我同意这是一件合理的事情。事实上,键入Common Lisp的序列函数(带有
:key
:test
)似乎需要这样的东西。然而,OCaml并不是一种可以实现这一点的语言

最合理的方法可能是编写两个函数,其中一个函数将访问器作为非可选参数,另一个函数提供
identity
作为该参数:

let g f x = f x

let g_default x = g identity x

这只是有点笨拙,您不需要在
g
中实现两次逻辑。但是,将这种方法应用于多个可选参数的组合将变得很难看。

谢谢Jeffrey。然而,实际具有类型
'a->'b
的函数不是用例所要求的。如果我将参数更改为
~accessor
,则
g1
中的
f
的类型是
'a->'b
,而较长示例中的
访问者的类型是
'a->'b
。这只意味着这个参数可以是任何函数,与函数在外部函数中必须做的事情兼容。如果我所要求的无法实现,那么这似乎只是OCaml的任意限制。(或者不是很武断:我相信这是有原因的。)是的,我想说的是OCaml中没有你想要的类型。据我所知。您只能在OCaml中定义具有OCaml类型的函数。我不能在OCaml中做我想要做的事情,但在我看来,将其描述为“没有类型…用于我想要的”的情况是不正确的
'a->'b
是一种OCaml类型,使用具有该类型的非可选参数定义函数是没有问题的
identity
具有该类型,以及更具体的类型
'a->'a
,因此我可以将
identity
作为参数传递给这样的函数:
让g f x=f x;;g恒等式2=2;;-:int=2
。然而,我不能给类型为
'a->'b
的可选参数指定
identity
作为默认值,即使它是该类型的一个实例。请为整个函数指定一个类型,而不仅仅是参数。啊,现在我明白你的意思了。那我想我应该说是。。。有趣的是,有些函数的类型是
('a->'b)->'a->'b
,但没有函数的类型是
?f:('a->'b)->'a->'b
,尽管唯一的区别是在第二种情况下,第一个参数是可选的。也许这是语法的产物?唯一允许您定义没有
选项
类型的可选参数的语法需要默认函数,其最特定的类型被视为参数的类型。谢谢gsg。我很好奇为什么不能这样做,但这和我问的问题不同。答案可能与OCaml类型系统的微妙之处有关。我怀疑这类事情在Common Lisp中要简单得多,因为它是动态类型的。原因其实很简单。可选参数完全扩展为模式匹配类型
option
。尝试编写一个函数,用类型为
\uoption
的参数实现您想要的专门化,您将看到您也无法做到这一点。
?f:('a -> 'b) -> 'a -> 'b
let g f x = f x

let g_default x = g identity x