Rust如何解决Hindley的可变性问题

我读过Rust使用Hindley-Milner的很好类型推断。 Rust也具有可变变量,而AFAIK在HM算法适用于可变性时必定存在一些约束,因为它可能过度泛化。 以下代码:

let mut a;
a = 3;
a = 2.5;

不编译,因为在第二行推荐了整数并且浮点值不能被分配给整数变量。 所以我猜测,对于简单变量,只要推断出非泛型类型,变量就变成单声道类型,不能再泛化了。

但是像Vec这样的模板呢? 例如这个代码:

let mut v;
v = Vec::new();
v.push(3);
v.push(2.3);

这再次失败,但最后一行。 这意味着第二行部分推断出类型(Vec),第三行推断出容器类型。

什么是规则? 有没有像我不知道的价值限制? 还是我过分复杂的事情和鲁斯有更严格的规则(就像没有泛化一样)?


它被认为是一个问题(就诊断质量而言),rustc在其类型推断中稍微过于热衷。

如果我们检查你的第一个例子:

let mut a = 3;
a = 2.5;

然后第一行导致推断a有一个{generic integer type} ,第二行将导致诊断2.5不能被分配给a因为它不是泛型整数类型。

预计一个更好的算法会改为注册冲突,然后指向每个类型出现的线。 也许我们会用粉笔来解决这个问题。

注意:泛型整数类型是Rust使整数文字“多态”的一个技巧,如果没有其他提示应该是什么特定的整数类型,它将默认为i32


第二个例子发生的方式基本相同。

let mut v = Vec::new();
v.push(3);

详细信息:

  • v被分配类型$T
  • Vec::new()产生Vec<$U>类型
  • 3产生类型{integer}
  • 所以,在第一行,我们得到$T == Vec<$U> ,在第二行我们得到$U == {integer} ,所以v被推断为Vec<{integer}>

    如果没有其他的来源来学习确切的整数类型,默认情况下会回到i32


    我想指出,可变性实际上并不影响推论。 从类型推断或类型统一的角度来看,以下代码示例是等效的:

    //  With mutability:
    let mut a = 1;
    a = 2.5;
    
    //  Without mutability:
    let a = if <condition> { 1 } else { 2.5 };
    

    对于HM来说,Rust中存在很多问题, Deref和sub-typing更具挑战性。


    如果我没有错,它会这样做:

    let mut a;
    a = 3;     //here a is already infered as mut int
    a = 2.5;   //fails because int != float
    

    对于vec片段:

    let mut v;
    v = Vec::new();// now v type is Vec<something>
    v.push(3);     // v type is Vec<int>
    v.push(2.3);   // here fails because Vec<int> != Vec<float>
    

    注意我没有使用铁锈类型,只是为了有个大概的想法。

    链接地址: http://www.djcxy.com/p/80887.html

    上一篇: How does Rust solve mutability for Hindley

    下一篇: Growth of Type Definition in SML Using Hindley Milner Type Inference