- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我正在开发一个用 Java 编写的基于数据流的简单系统(想象它就像一个 LabView 编辑器/运行时)。用户可以在编辑器中将 block 连接在一起,我需要类型推断来确保数据流图是正确的,然而,大多数类型推断示例都是用数学符号、ML、Scala、Perl 等编写的,我不会“说” ".
我阅读了 Hindley-Milner 算法并找到了 this文档中有一个我可以实现的很好的例子。它适用于一组类似 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-ish 示例或解释。
最佳答案
我至少阅读了 20 篇文章并找到了一篇(Francois Pottier:存在子类型的类型推断:从理论到实践)我可以使用:
输入:
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 计算两个具体类型的公共(public)子类型,例如,(Object, Serializable) == Object&Serializable, (Integer, String) == null。
交集计算两个具体类型的最近父类(super class)型,例如,(List, Set) == Collection, (Integer, String) == Object。
SubC 是结构分解函数,在这个简单的例子中,它只会返回一个包含其参数的新 TypeRelation 的单例列表。
跟踪结构:
UpperBounds = Map<TypeVariable, Set<Type>>
LowerBounds = Map<TypeVariable, Set<Type>>
Reflexives = List<TypeRelation>
UpperBounds 跟踪可能是类型变量的父类(super class)型的类型,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 的 LowerBounds 设置为 String。 T 的 UpperBounds 不存在,因此,TypeRelations 保持不变。
2.) rel 是 (Integer, T);情况 3 再次激活。 Reflexives 仍然为空,T 的下限设置为 String 和 Integer 的交集,产生 Object,仍然没有 T 的上限并且 TypeRelations 没有变化
3.) rel 是 T >= U。案例 1 被激活。因为 Reflexives 为空,T 的上界与 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。情况 2 被激活。该案例试图将 T 的上界(此时为对象)与 Integer 结合,但失败了,算法也失败了。
类型系统的扩展
将泛型类型添加到类型系统需要在主要情况和 SubC 函数中进行扩展。
Type = { TypeVariable, ConcreteType, ParametricType<Type,...>)
一些想法:
关于java - Java 中的 Hindley-Milner 算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6783463/
我发誓曾经有一件T恤出售,上面写着不朽的文字: 哪一部分 你不明白吗? 就我而言,答案是......全部! 特别是,我经常在 Haskell 论文中看到这样的符号,但我不知道它的含义。我不知道它应该是
考虑以下程序(在 Haskell 中,但可以是任何 HM 推断的语言): x = [] y = x!!0 使用 HM(或通过运行编译器),我们推断: x :: forall t. [t] y :: f
在 Haskell 中,我们可以编写以下数据类型: data Fix f = Fix { unFix :: f (Fix f) } 类型变量f有种* -> * (即它是一个未知类型的构造函数)。因此,
let a = b in c可以被认为是 (\a -> c) b 的语法糖。 ,但在一般的打字设置中,情况并非如此。例如,在米尔纳微积分 let a = \x -> x in (a True, a 1
我正在制作一种强类型玩具函数式编程语言。它使用 Hindley Milner 算法作为类型推断算法。 实现算法时,我有一个问题是如何推断相互递归函数的类型。 let rec f n = if n ==
我正在阅读关于 Hindley–Milner Type Inference 的维基百科文章试图从中找出一些道理。到目前为止,这是我所理解的: 类型分为单型或多型。 Monotype 进一步分类为类型常
我试图推断以下表达式的类型: let rec fix f = f (fix f) 应指定类型(a -> a) -> a 使用自下而上算法(在概括hindley-milner类型推理算法中描述)并添加以
我正在寻找关于著名 Damas-Hindley-Milner algorithm 的信息为函数式语言进行类型推断,尤其是关于实现的信息。 我已经知道如何执行 Algorithm W ,但我听说最近的新
当存在重载函数时,Hindley-Milner 算法如何工作? 以简单的形式(没有重载),它看起来很干净: y = arr[x1] //it's Generic. x1: int, arr: T[],
我正在尝试通过用我常用的语言 Clojure 实现算法 W 来自学 Hindley-Milner 类型推理。我遇到了 let 推理的问题,我不确定我是否做错了什么,或者我期望的结果是否需要算法之外的东
如果我正确理解 Haskell 中的 ST monad,runST 以巧妙的方式使用 2 级类型,以确保计算在转义 monad 时不会引用任何其他线程。 我有一种带有 Hindley-Milner 类
我正在尝试通过用我常用的语言 Clojure 实现算法 W 来自学 Hindley-Milner 类型推理。我遇到了 let 推理的问题,我不确定我是否做错了什么,或者我期望的结果是否需要算法之外的东
我读到 Rust 使用 Hindley-Milner 有很好的类型推断。 Rust 也有可变变量,据我所知,当 HM 算法处理可变性时必须有一些约束,因为它可能过度泛化。以下代码: let mut a
我正在开发一个用 Java 编写的基于数据流的简单系统(想象它就像一个 LabView 编辑器/运行时)。用户可以在编辑器中将 block 连接在一起,我需要类型推断来确保数据流图是正确的,然而,大多
我无法理解维基百科上给出的 HM 系统的 letrec 定义,这里:https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system#R
下'What is Hindley Milner'它指出: Hindley-Milner is a restriction of System F, which allows more types b
PyPy 是否在编译时进行静态类型检查以在编译时捕获类型错误?如果不是,像 HM 类型推断这样的东西是否有助于在编译时捕获这些错误? 最佳答案 否 在两个帐户上。 (我假设 PyPy 是指具有 JIT
我最近一直在学习 λ 演算。我理解无类型和有类型 λ 演算之间的区别。但是,我不太清楚 之间的区别。 Hindley-Milner 型系统 和 类型化 λ 演算 .是关于parametric poly
Hindley-Milner 是一个类型系统,它是许多众所周知的函数式编程语言的类型系统的基础。 Damas-Milner 是一种在 Hindley-Milner 类型系统中推断(推导出?)类型的算法
有人曾经在 SML 中向我展示了一个小技巧,他们在他们的 REPL 中写出了大约 3 或 4 个函数,最后一个值的结果类型非常长(就像许多页面滚动很长)。 有谁知道什么代码会生成这么长的类型,或者是否
我是一名优秀的程序员,十分优秀!