类型推断是如何在 C++11 或 Go 等语言中实现的?

Jon*_*low 0 compiler-construction algorithm type-inference

我在这里看到了这个问题,但它没有特别详细地回答我的想法。如果像 Go 或 C++11 这样的语言不使用像 Damas-Milner 这样的推理算法,它们究竟做了什么?我认为这不像在右手边输入类型那么简单,因为如果你有这样的东西怎么办:

5 + 3.4
Run Code Online (Sandbox Code Playgroud)

编译器如何破译那是什么类型?有没有什么算法不那么简单

if left is integer and right is float:
    return float;
if left is float and right is integer:
    return float;
etc... for every possible pattern
Run Code Online (Sandbox Code Playgroud)

如果你能用简单的术语解释事情,那就太好了。我没有详细研究编译器构造或任何理论主题,我也不会真正讲函数式语言或复杂的数学符号。

sep*_*p2k 5

我认为这不像在右手边取字那么简单

对于表单的基本类型推断auto var = some_expression;,就是这么简单。每个类型良好的表达式都只有一种类型,并且该类型将是var. 不会有从表达式类型到另一种类型的隐式转换(如果您为 指定了显式类型,则可能会发生这种情况var)。

如果你有类似的东西怎么办:

5 + 3.4
Run Code Online (Sandbox Code Playgroud)

问题“什么是类型5 + 3.4?” 并非特定于类型推断,C++ 编译器总是必须回答这个问题 - 甚至在引入类型推断之前。

因此,让我们退后一步,看看 C++ 编译器如何对语句进行类型检查some_type var = some_expression;

首先它确定some_expression. 所以在代码中你可以想象像Type exp_type = type_of(exp);. 现在它检查是否exp_type等于some_type或存在从exp_typeto的隐式转换some_type。如果是这样,则该语句是类型良好的,并var作为具有 type 引入环境中some_type。否则不是。

现在,当我们引入类型推断和 write 时auto var = some_expression;,等式发生了变化:我们仍然这样做Type exp_type = type_of(exp);,但不是将其与另一种类型进行比较或应用任何隐式转换,而是简单地将其设置exp_type为 的类型var

所以现在让我们回到5 + 3.4. 它的类型是什么,编译器如何确定它?在 C++ 中,它的类型是double. C++ 标准中列出了确定算术表达式类型的确切规则(查找“通常的算术转换”),但基本上归结为:在两种操作数类型中,选择一种可以表示更大范围的操作数类型值。如果类型小于int,则将两个操作数都转换为int。否则,将两个操作数都转换为您选择的类型。

在代码中,您可以通过为每个数字类型分配一个转换等级然后执行以下操作来实现这一点:

Type type_of_binary_arithmetic_expression(Type lhs_type, Type rhs_type) {
    int lhs_rank = conversion_rank(lhs_type);
    int rhs_rank = conversion_rank(rhs_type);
    if(lhs_rank < INT_RANK && rhs_rank < INT_RANK) return INT_TYPE;
    else if(lhs_rank < rhs_rank) return rhs_type;
    else return lhs_type;
}
Run Code Online (Sandbox Code Playgroud)

想必围棋的规则有些不同,但适用相同的原则。