2011-12-05 65 views
3

我想写可选择接受一个函数作为参数ocaml的任何类型的匹配

let xxx ?(extractor = (fun a -> a)) yyy = ... 

这最终有类型的函数:

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

我的目的是让提取到是一个从结构中提取信息的函数,所以返回类型可以是任何东西,但我希望默认是身份函数

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

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

但它没有编译,说(a - >'a)与(a' - >'b)不兼容。我觉得奇怪的是('a - >'a)不是(a' - >'b)的子集。有没有我可以放在mli文件中的语法('a - > *)?

回答

3

在函数式语言中,您从函数中返回的未指定(变量)类型基本上必须出现在您传递的类型中的某处,否则值会从何处来?因此,没有(有用的)功能类型'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 

这有你想要的行为:默认提取函数是标识函数。但是这也迫使返回类型f与其输入类型相同。因此XXX的类型是:

val xxx : ?extractor:('a -> 'a) -> 'a -> 'a 

除非你想获得极其花哨,没什么解决这个没办法了,我怀疑一个奇特的解决方案将提出一份超过具有可选参数的便利性复杂性。

也许它会工作有两个功能。要继续简化的例子,他们是这样的:

# 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> 

我觉得这有你想要的类型,唯一的不便是,你有两个不同的名字。

+1

'所以没有(有用的)类型'a - >'b.'的功能 - 有一个非常有用的魔术功能(但我不会在这里称呼它!):) – ygrek

+0

我知道这个函数,我只是认为它在语言之外(从某种意义上说)。 –

+0

同意了,这更像是一个笑话 – ygrek

2

我的目的是让提取器是提取的结构 信息的功能,因此,返回类型可以是任何东西,但 我希望默认是身份的功能

O_PONIES ?返回类型的标识函数不能是什么东西,它正好是东西传递给它。 ('a - >'a)不是(a' - >'b)的子集,我觉得很奇怪。如果你想用类型B约束类型A,那么类型B的每个实例都应该是类型A的实例,即类型B应该是类型A的子集(换句话说 - 比它更窄)类型A(不是另一方面)。在你的情况下('a - >'b)不是('a - >'a)的子集。这与LSP有关,但直觉就足以解决这个问题。

3

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

你有什么没有意义的原因是,让我们假设该函数用于上下文中要求'aint'bstring。您的默认参数fun a -> a不能满足所需的类型int -> string。无论你放置什么,都必须适用于任何类型变量的组合,但正如其他人所提到的那样,使用任何类型的函数并返回任何其他所需的类型都没有意义。

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