繁体   English   中英

F#编译器如何/何时预读类型推断?

[英]How/when does the F# compiler read ahead for type inference?

如果我在下面创建添加功能

let add x y =
    x + y

然后单独运行下面的行,我会收到一个错误,因为F#默认假设x和y应该是整数。

add 5.4 3.2

也就是说,如果我一起运行它们,添加工作就好了,因为它现在将其视为一个获得两个浮点数的函数(这意味着编译器向前看进行类型推断)。

这引出了一个问题,为什么不同的向前看过程允许F#知道toHackerTalk正在接受一个字符串? 即使我一起运行以下行,它也会给我一个错误,因为短语的类型是不确定的。

let toHackerTalk phrase =
    phrase.Replace('t', '7').Replace('o', '0')

toHackerTalk "this be strange"

我认为这是对此的简单看法。 在第一种情况下,编译器知道+ (它在F#核心中定义)并且它只是选择一个默认类型的int (可能在某个地方的规范中定义),如果它然后看到float使用,不同版本的+被选中。

另一方面,编译器没有足够的信息来选择具有Replace成员的类型,因此无法编译该函数

该规范在5.2.3节中提到了这种行为:

除非将定义标记为内联,否则重载运算符的使用不会产生通用代码。 例如,功能

  let fx = x + x 

导致函数f只能用于添加一种类型的值,例如int或float。 确切的类型由后来的约束决定。

一般来说,只要编译器推断出由于某种原因而无法真正通用的“通用”定义,就会出现这个问题。 在使用像(+)之类的运算符的情况下,有一个静态成员约束,它阻止add是泛型的,除非它也是inline声明的。

另一种出现这种限制的情况是:

let d = System.Collections.Generic.Dictionary()

d.[0] <- "test"

如果你一起评估这些行, d将是一个Dictionary<int,string> ,但如果你单独评估它们,你会在评估第二个时得到一个错误,因为d将被推断为一个Dictionary<obj,obj> 根据它的定义, d可以是任何'a'bDictionary<'a,'b> ,但它不是通用定义,因为没有通用值这样的东西(好吧,差不多;参见[<GeneralizableValue>]使用[<GeneralizableValue>]例外)。

基于很久以前对规范的解读,我的理解是编译器实际上并没有向前看,而是在它出现时创建类型变量,识别每个变量的约束,然后将实际类型分配给变量看完一切后。 所以在第二种情况下,当它读取add定义时,它会为参数创建类型变量'a'b 然后它进入调用add 5.4 3.2 ,它将'a'b都限制为float

编译时, let add xy = x + y ,没有什么可以约束类型,所以编译器选择int

由于在读取整个编译单元后解决了类型约束,因此可以通过说“始终”来回答您的问题。 您正在质疑的行为只出现在F#interactive中,其中编译单元较小。 编译是以位而不是一次完成的。

add的情况下,编译器将参数类型默认为int 如果您改为编写let inline add xy = x + y ,编译器将自动将xy的类型概括为实现+运算符的类型。 这是静态解析的类型参数的示例。 当默认addint的参数类型时,F#将在当前范围内查找。

str.Replace的情况下,方法Replace是string上的实例方法。 因此,编译器必须知道str的类型以对其实例方法做出任何确定。 或者,在上面的示例中, +是一个静态函数 - 编译器知道前面涉及的类型和约束。 有关F#类型推断的更多信息,请查看此处

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM