什么是泛型的F#类型推断方法?

Jef*_*eff 1 f# type-inference static-typing typechecking hindley-milner

我想了解有关类型推断的规则,因为我希望将其纳入自己的语言中,并且本着这种精神,我一直在研究F#的类型推断,以下让我感到奇怪。

这将进行编译,并且id'a -> 'a,(如果我没有记错的话)表示每个调用都使用“新鲜”类型。

let id x = x

let id1 = id 1
let id2 = id "two"
Run Code Online (Sandbox Code Playgroud)

但是,当使用运算符时,似乎是第一次调用确定了该函数的签名。

在这里,mul据报道是int -> int -> int

let mul x y = x * y

let mul1 = mul 1 2
let mul2 = mul 1.1 2.2 // fails here
Run Code Online (Sandbox Code Playgroud)

如果我重新排序,mul则为float -> float -> float

let mul x y = x * y

let mul2 = mul 1.1 2.2
let mul1 = mul 1 2 // fails here
Run Code Online (Sandbox Code Playgroud)

您能从类型检查实现的角度解释(最好是非学术性的)术语是什么规则,以及规则如何工作?它是否遍历函数以在每次引用时检查其类型?还是有其他方法?

sep*_*p2k 5

First note that this will not happen if we declare mul as an inline function:

let inline mul x y = x * y

let mul1 = mul 1 2  // works
let mul2 = mul 1.1 2.2 // also works
Run Code Online (Sandbox Code Playgroud)

Here the inferred type of mul will be as follows:

x: ^a -> y: ^b ->  ^c
    when ( ^a or  ^b) : (static member ( * ) :  ^a *  ^b ->  ^c)
Run Code Online (Sandbox Code Playgroud)

This type means that the parameters x and y can have any type (doesn't even have to be the same type) as long as at least one of them has a static member named * that takes arguments of the same types as x and y. The return type of mul will be the same as that of the * member.

So why don't you get the same behavior when mul isn't inline? Because member constraints (i.e. type constraints that say that a type must have specific members) are only allowed on inline functions - that's also why the type variables have a ^ in front instead of the usual ': to signify that we're dealing with a different, less limited kind of type variable.

那么为什么存在对非内联函数的限制呢?由于.NET支持。类型约束(例如“ T实现接口I”)可以在.NET字节码中表示,因此可以在所有函数中使用。类型约束(例如“ T必须具有名为U的特定成员,且类型为X的X”)无法表达,因此在普通函数中是不允许的。由于内联函数在生成的.NET字节码中没有相应的方法,因此不需要在.NET字节码中表示它们的类型,因此限制并不适用于它们。