Har*_*til 1 polymorphism ocaml types reason
我注意到ReasonML中的类型推断机制非常奇怪的行为。我有一条包含识别功能的记录。当我直接使用记录实例时,编译器不会抱怨。但是,当我将记录传递给另一个函数并尝试调用标识函数时,则键入推断会抱怨:
type idRecord('a) = {
// idFn can take any type.
idFn: 'a => 'a
};
let myRecord: idRecord('a) = {
idFn: anyVal => anyVal
};
// WORKS ABSOLUTELY FINE
let x1 = myRecord.idFn(10);
let x2 = myRecord.idFn("Something");
let runProgram = (program: idRecord('a)) => {
let _y1 = program.idFn(10);
// BOOM: ERROR
// This expression has type string but an expression was expected of type int
let _y2 = program.idFn("Something");
}
runProgram(myRecord);
Run Code Online (Sandbox Code Playgroud)
错误是:
该表达式的类型为字符串,但预期为int类型的表达式
我需要怎样使类型推断高兴地接受任何类型的参数?
根本问题是您的函数runProgram是第二多态的,换句话说,使用多态函数作为参数有点复杂。
更严重的是,在幻想语法中,的类型runProgram将是('a. 'a => 'a)=> unitwhere 'a. 'a => 'a表示为any工作所需的功能'a。这与像
let apply: 'a. ('a -> 'a) -> 'a -> 'a = (f, x) => f(x)
Run Code Online (Sandbox Code Playgroud)
'a首先引入类型变量(在prenex位置),然后要求function参数仅在此特定类型上起作用'a。例如
let two = apply( (x)=> 1 + x, 1)
Run Code Online (Sandbox Code Playgroud)
即使(x)=> 1 + x仅适用于整数也有效。鉴于
let fail = runProgram((x) => 1 + x)
Run Code Online (Sandbox Code Playgroud)
失败,因为(x) => 1 + x无法使用字符串。
回到类型推断问题,类型检查器未能推断出您所记住的类型的原因是类型推断和高阶多态性不能很好地融合(更确切地说,在存在高阶多态性的情况下,类型推断是无法确定的)。要了解原因,请考虑以下简单功能
let ambiguous(f,x) = f(1)+f(x)
Run Code Online (Sandbox Code Playgroud)
该类型的类型检查的推断ambiguous就是(int=>int)=>int=>int。但是,如果我替换f为具有多态字段的记录(这是在OCaml中编写高阶多态函数的两种方法之一)
type const = {f:'a. 'a => int}
let ambiguous({f},x) = f(1)+f(x)
Run Code Online (Sandbox Code Playgroud)
ambiguous(以幻想语法)的类型变为('a.'a=>int)=>'a=>int。换句话说,如果类型推断能够推断更高级别的多态性,则必须在('a.'a=>int)=>'a=>int和之间进行选择(int=>int)=>int=>int。两种类型之间没有明显的赢家:第一种类型对其第一个参数具有严格的约束,而第二个参数则较宽松,而第二种则完全相反。这是具有较高级别多态性的通用问题:有很多潜在选择,而没有明显的最佳选择。
这就是为什么在编写高级多态函数时,类型检查程序必须非常明确的原因:
type program = { program: 'a. 'a => 'a }
let runProgram = ({program}) => {
let _y1 = program(10);
let _y2 = program("Something");
}
Run Code Online (Sandbox Code Playgroud)
另请参见OCaml手册,网址为http://caml.inria.fr/pub/docs/manual-ocaml/polymorphism.html#sec61。