Types ocaml任何匹配的类型

Types ocaml任何匹配的类型,types,ocaml,Types,Ocaml,我正在尝试编写一个函数,可以选择将函数作为参数 let xxx ?(extractor = (fun a -> a)) yyy = ... 这最终会产生以下类型: val xxx: ?extractor:('a -> 'a) -> 'c -> ... 我的意图是让提取器成为一个从结构中提取信息的函数,因此返回类型可以是任何类型,但我希望默认值是identity函数 我试图在mli中将其签名更改为 val xxx: ?extractor:('a -> 'b) -&

我正在尝试编写一个函数,可以选择将函数作为参数

let xxx ?(extractor = (fun a -> a)) yyy = ...
这最终会产生以下类型:

val xxx: ?extractor:('a -> 'a) -> 'c -> ...
我的意图是让提取器成为一个从结构中提取信息的函数,因此返回类型可以是任何类型,但我希望默认值是identity函数

我试图在mli中将其签名更改为

val xxx: ?extractor:('a -> 'b) -> 'c -> ...

但是它没有编译,说('a->'a)与(a'->'b)不兼容。我觉得奇怪('a->'a)不是(a'->'b)的子集。在函数语言中,从函数返回的未指定(变量)类型基本上必须出现在传入的类型中的某个地方。否则,价值从何而来?因此,没有类型为
'a->'b的(有用的)函数。

考虑一下您希望传递给函数的类型,以及提取器函数与这些类型的关系,可能会有所帮助。应该可以有一个相当直接的关系。与类型系统抗争通常意味着您试图做一些可能意外失败的事情,这正是类型系统试图阻止的

编辑:

也许我想说的是,
'a
'b
,提取器函数的输入和输出类型,不会是任意类型。输入类型
'a
可能与类型
'c
有关。类似地,结果类型
'b
可能与函数的返回类型
xxx
作为一个整体相关。如果没有更多关于这些关系的信息,就很难提出建议

如果你试着把它们看作是独立的、任意的类型,你就会遇到我上面提到的参数不可能性。(它还需要高级输入,我想是2级多态性。)

作为一个简单的例子,假设
'a
'c
是相同的类型,
'b
是函数的返回类型。然后,您的函数必须看起来像这样:

let xxx ?extractor s =
    match extractor with
    | Some f -> f s
    | None -> s
# let xxx extractor s = extractor s;;
val xxx : ('a -> 'b) -> 'a -> 'b = <fun>
# let xxx_id s = xxx (fun x -> x) s;;
val xxx_id : 'a -> 'a = <fun>
这具有您想要的行为:默认的提取器函数是identity函数。但这也迫使
f
的返回类型与其输入类型相同。所以xxx的类型是:

val xxx : ?extractor:('a -> 'a) -> 'a -> 'a
除非你想变得非常花哨,否则真的没有办法解决这个问题,我怀疑一个花哨的解决方案会带来复杂性,这将超过拥有可选参数的便利性

也许它有两个功能。要继续简化示例,它们如下所示:

let xxx ?extractor s =
    match extractor with
    | Some f -> f s
    | None -> s
# let xxx extractor s = extractor s;;
val xxx : ('a -> 'b) -> 'a -> 'b = <fun>
# let xxx_id s = xxx (fun x -> x) s;;
val xxx_id : 'a -> 'a = <fun>
#让xxx提取器s=提取器s;;
val xxx:('a->'b)->'a->'b=
#让xxx_id s=xxx(乐趣x->x)s;;
val xxx_id:'a->'a=
我想这些都是你想要的类型,唯一的不便是你有两个不同的名字

我的意图是让提取器成为一个函数,用于提取 来自结构的信息,因此返回类型可以是任何类型,但 我希望默认值是identity函数

小马?标识函数的返回类型不能是任何东西,它正是传递给它的某物

我觉得奇怪('a->'a)不是(a'->'b)的子集


如果您想用类型B约束类型A,那么类型B的每个实例都应该是类型A的实例,即类型B应该是类型A的子集(换句话说,比类型A更窄)(而不是相反)。在您的情况下('a->'b)不是('a->'a)的子集。这与LSP有关,但只要凭直觉就足以解决这一问题。

当函数签名具有类型变量,如
'a
'b
等时,这并不意味着函数可以在运行时将任何类型放入其中。相反,这意味着来自外部的人可以告诉函数这些类型变量中的每一个是什么类型的,并且无论它说什么,函数仍然能够正确工作。(有人是类型检查器,它根据使用函数的上下文设置类型。)

您所拥有的没有意义的原因是,假设函数在要求
'a
int
'b
字符串的上下文中使用。默认参数
funa->a
,无法满足所需的类型
int->string
。无论您在那里放置什么,都必须适用于任何类型变量的组合,但正如其他人所提到的,拥有一个接受任何类型并返回任何其他所需类型的函数是没有意义的


我认为您需要的是两个独立的函数,一个有额外参数,另一个没有,后者使用
funa->a
作为额外参数调用前者。请注意,没有额外参数的函数将在其类型中减少一个类型变量,因为它不再分别有
'a
'b

因此没有类型为'a->'b的(有用的)函数。
--只有一个非常有用的神奇函数(但我不会在这里直呼其名!)我知道这个函数,我只是认为它在语言之外(在某种意义上)。