欣德利-米尔纳算法在Java



我正在用Java编写一个简单的基于数据流的系统(想象它像一个LabView编辑器/运行时)。用户可以在编辑器中将块连接在一起,我需要类型推断来确保数据流图是正确的,然而,大多数类型推断示例都是用数学符号编写的,ML, Scala, Perl等,我不会"说话"。

我读了辛德雷-米尔纳算法,发现这个文档有一个很好的例子,我可以实现。它适用于一组T1 = T2的约束。然而,我的数据流图像约束一样转换为T1>= T2(或T2扩展T1,或协方差,或T1 <: T2,正如我在各种文章中看到的那样)。没有lambda,只有类型变量(用于像T merge(T in1, T in2)这样的泛型函数)和具体类型。

回顾一下HM算法:

Type = {TypeVariable, ConcreteType}
TypeRelation = {LeftType, RightType}
Substitution = {OldType, NewType}
TypeRelations = set of TypeRelation
Substitutions = set of Substitution
1) Initialize TypeRelations to the constraints, Initialize Substitutions to empty
2) Take a TypeRelation
3) If LeftType and RightType are both TypeVariables or are concrete 
      types with LeftType <: RightType Then do nothing
4) If only LeftType is a TypeVariable Then
    replace all occurrences of RightType in TypeRelations and Substitutions
    put LeftType, RightType into Substitutions
5) If only RightType is a TypeVariable then
    replace all occurrences of LeftType in TypeRelations and Substitutions
    put RightType, LeftType into Substitutions
6) Else fail

我如何改变原来的HM算法来处理这些关系,而不是简单的相等关系?如能提供java样例或解释,则不胜感激。

我阅读了至少20篇文章,并找到了一篇我可以使用的文章(Francois Pottier: Type inference in presence of subtyping: from theory to practice):

输入:

Type = { TypeVariable, ConcreteType }
TypeRelation = { Left: Type, Right: Type }
TypeRelations = Deque<TypeRelation>

辅助功能:

ExtendsOrEquals = #(ConcreteType, ConcreteType) => Boolean
Union = #(ConcreteType, ConcreteType) => ConcreteType | fail
Intersection = #(ConcreteType, ConcreteType) => ConcreteType
SubC = #(Type, Type) => List<TypeRelation>

ExtendsOrEquals可以告诉我们两个具体的类型,如果第一个扩展或等于第二个,例如,(String, Object) == true, (Object, String) == false。

Union计算两个具体类型的公共子类型,如(Object, Serializable) == Object&Serializable, (Integer, String) == null。

交集计算两个具体类型最近的超类型,例如(List, Set) == Collection, (Integer, String) == Object。

SubC是结构分解函数,在这个简单的例子中,它将返回一个单例列表,其中包含其参数的一个新的typeelation。

跟踪结构:

UpperBounds = Map<TypeVariable, Set<Type>>
LowerBounds = Map<TypeVariable, Set<Type>>
Reflexives = List<TypeRelation>

UpperBounds跟踪可能是类型变量的超类型的类型,LowerBounds跟踪可能是类型变量的子类型的类型。Reflexives跟踪对类型变量之间的关系,以帮助算法的边界重写。

算法如下:

While TypeRelations is not empty, take a relation rel
  [Case 1] If rel is (left: TypeVariable, right: TypeVariable) and 
           Reflexives does not have an entry with (left, right) {
    found1 = false;
    found2 = false
    for each ab in Reflexives
      // apply a >= b, b >= c then a >= c rule
      if (ab.right == rel.left)
        found1 = true
        add (ab.left, rel.right) to Reflexives
        union and set upper bounds of ab.left 
          with upper bounds of rel.right
      if (ab.left == rel.right)
        found2 = true
        add (rel.left, ab.right) to Reflexives
        intersect and set lower bounds of ab.right 
          with lower bounds of rel.left
    if !found1
        union and set upper bounds of rel.left
          with upper bounds of rel.right
    if !found2
        intersect and set lower bounds of rel.right
          with lower bounds of rel.left
    add TypeRelation(rel.left, rel.right) to Reflexives
    for each lb in LowerBounds of rel.left
      for each ub in UpperBounds of rel.right
        add all SubC(lb, ub) to TypeRelations
  }
  [Case 2] If rel is (left: TypeVariable, right: ConcreteType) and 
      UpperBound of rel.left does not contain rel.right {
    found = false
    for each ab in Reflexives
      if (ab.right == rel.left)
        found = true
        union and set upper bounds of ab.left with rel.right
    if !found 
        union the upper bounds of rel.left with rel.right
    for each lb in LowerBounds of rel.left
      add all SubC(lb, rel.right) to TypeRelations
  }
  [Case 3] If rel is (left: ConcreteType, right: TypeVariable) and
      LowerBound of rel.right does not contain rel.left {
    found = false;
    for each ab in Reflexives
      if (ab.left == rel.right)
         found = true;
         intersect and set lower bounds of ab.right with rel.left
    if !found
       intersect and set lower bounds of rel.right with rel.left
    for each ub in UpperBounds of rel.right
       add each SubC(rel.left, ub) to TypeRelations
  }
  [Case 4] if rel is (left: ConcreteType, Right: ConcreteType) and 
      !ExtendsOrEquals(rel.left, rel.right)
    fail
  }

一个基本例子:

Merge = (T, T) => T
Sink = U => Void
Sink(Merge("String", 1))

表达式的关系:

String >= T
Integer >= T
T >= U

1.) rel = (String, T);案例3被激活。因为Reflexives为空,所以T的下限被设置为String。没有T的上限,因此,类型关系保持不变。

2.) rel = (Integer, T);案例3再次被激活。Reflexives仍然为空,T的下界设置为String和Integer的交集,生成Object, T仍然没有上界,TypeRelations也没有变化

3.) rel = T>= u。因为Reflexives为空,所以T的上界与U的上界结合在一起,U的上界仍然为空。然后将下界U设置为T的下界,产生Object>= U。将TypeRelation(T, U)添加到Reflexives中。

4.),算法终止。从边界Object>= T和Object>= U

在另一个示例中,演示了类型冲突:

Merge = (T, T) => T
Sink = Integer => Void
Sink(Merge("String", 1))

的关系:

String >= T
Integer >= T
T >= Integer

步骤1.)和步骤2.)与上述相同。

3.) rel = T>= u。这种情况试图将T的上界(此时是Object)与Integer合并,但失败了,算法也失败了。

Type系统的扩展

向类型系统添加泛型类型需要在主用例和SubC函数中进行扩展。

Type = { TypeVariable, ConcreteType, ParametricType<Type,...>)

的一些想法:

  • 如果一个ConcreteType和一个parametertype同时满足,则报错。
  • 如果TypeVariable和parametertype满足,例如T = C(U1,…,Un),则创建新的Type变量和关系T1>= U1,…, Tn>= Un,并与他们合作。
  • 如果两个parametertype满足(D<>和C<>),检查D>= C和类型参数的数量是否相同,然后提取每对作为关系。

Hindley-Milner算法本质上是一种统一算法,即求解带有变量的图方程的图同构的算法。

欣德利-米尔纳并不直接适用于你的问题,但谷歌搜索发现了一些线索;如。"多态语言中的语用子类型",其中说"我们提出了一种基于名称不等价的hinley/Milner类型系统的子类型扩展…"。(我还没读过。)


…然而,大多数类型推断示例都是用数学符号编写的,ML, Scala, Perl等,我不会"说"。

我认为你必须自己克服这个障碍。类型理论和类型检查基本上都是数学问题。而困难的。你需要努力学习这门语言。

最新更新