此F#代码编译时没有出现错误
type A() =
member private this.M1(tt: Task<'t>) = task {
let! t = tt
return t
}
member this.M4() = this.M2()
member this.M2() = this.M1(Task.FromResult(1))
member this.M3() = this.M1(Task.FromResult(1.0))
M4调用之后声明的M2。现在我移动最后的私有方法:
type A() =
member this.M4() = this.M2()
member this.M2() = this.M1(Task.FromResult(1)) //FS0064
member this.M3() = this.M1(Task.FromResult(1.0)) //FS0001
member private this.M1(tt: Task<'t>) = task { //FS0064
let! t = tt
return t
}
此代码编译时没有出现以下错误:
警告FS0064此构造导致代码的泛型低于类型>注释。类型变量"t"已被约束为类型"int"。
错误FS0001此表达式应具有类型"int",但此处具有类型"float">
请解释发生这种情况的原因以及如何修复(如果可能(
F#编译器是单次通过的,包括它的类型推断。它根据程序从头到尾的使用情况来确定类型,并且不会重复(rec
绑定或模块除外(。
在您的特定示例中,当编译器遇到方法M2
时,它在其主体中看到方法M1
是用类型为Task<int>
的参数调用的,因此它推断M1 : Task<int> -> 'a
对于一些未知的'a
当谈到方法M3
的主体时,它看到M1
是用类型为Task<float>
的参数调用的,而这与它已经确定的类型信息不匹配,因此它发出了一个错误。
当它稍后谈到M1
本身的定义时,它看到参数被声明为泛型。但是编译器已经知道参数必须是Task<int>
,所以泛型参数't
必须总是等于int
,这就是它告诉你的:">类型变量"t"已被约束为类型"int">"。它发出了一个警告,因为很明显,如果你想让它是通用的,但它实际上是具体的,那么肯定有什么地方出了问题。
这种单向行为并不是一种缺陷或疏忽,它在很大程度上是故意的。这使得编译器更简单、更快、更高效,而且作为额外的好处,它通常会强制实现良好的程序结构。