我遇到了这个词 Hindley-Milner ,我不确定是否掌握了它的含义。
我已阅读以下帖子:
但维基百科中没有单一的条目,通常会给我一个简明的解释 注意 - 一个人有now been added
这是什么? 哪些语言和工具可以实现或使用它? 请您提供简明的答案?
答案 0 :(得分:156)
Hindley-Milner是一个类型的系统,由Roger Hindley独立发现(他正在研究逻辑),后来由Robin Milner(正在研究编程语言)发现。 Hindley-Milner的优点是
支持多态功能;例如,一个函数可以为您提供独立于元素类型的列表长度,或者函数执行二叉树查找,而不依赖于树中存储的键的类型。
有时函数或值可以有多个类型,如长度函数的示例:它可以是“整数列表整数”,“字符串列表到整数“,”对整数列表“,依此类推。在这种情况下,Hindley-Milner系统的一个信号优势是每个良好类型的术语都具有唯一的“最佳”类型,这被称为主要类型。 list-length函数的主要类型是“for a
,函数从a
到整数”。这里a
是一个所谓的“类型参数”,它在lambda演算中是显式的,但在大多数编程语言中是隐式的。类型参数的使用解释了为什么Hindley-Milner是一个实现 参数多态性的系统。 (如果在ML中编写长度函数的定义,则可以看到类型参数:
fun 'a length [] = 0
| 'a length (x::xs) = 1 + length xs
如果一个术语具有Hindley-Milner类型,则可以推断出主体类型,而无需任何类型声明或程序员的其他注释。 (这是一种喜忧参半的祝福,因为任何人都可以证明,他们曾经处理过很多没有注释的ML代码。)
Hindley-Milner是几乎所有静态类型函数式语言类型系统的基础。常用的这类语言包括
所有这些语言都扩展了Hindley-Milner; Haskell,Clean和Objective Caml以雄心勃勃和不寻常的方式这样做。 (需要扩展来处理可变变量,因为基本的Hindley-Milner可以使用例如包含未指定类型的值列表的可变单元来破坏。这些问题由称为value restriction的扩展来处理。 。)
许多其他基于类型化函数语言的次要语言和工具都使用Hindley-Milner。
Hindley-Milner是System F的限制,它允许更多类型但需要程序员注释。
答案 1 :(得分:8)
您可以使用Google学术搜索或CiteSeer或您当地的大学图书馆查找原始论文。第一个是足够大,你可能必须找到期刊的绑定副本,我无法在网上找到它。我找到的另一个链接被打破了,但可能还有其他链接。你当然能找到引用这些文章的论文。
Hindley,Roger J,组合逻辑中对象的主要类型方案, 交易美国数学学会,1969年。
Milner,Robin, A型多态性,计算机与系统科学学报,1978。
答案 2 :(得分:5)
C#中的简单Hindley-Milner类推理实现:
Hindley-Milner type inference over (Lisp-ish) S-expressions, in under 650 lines of C#
请注意,实现的范围只有大约270行C#(对于算法W本身和支持它的少数数据结构,无论如何)。
用法摘录:
// ...
var syntax =
new SExpressionSyntax().
Include
(
// Not-quite-Lisp-indeed; just tolen from our host, C#, as-is
SExpressionSyntax.Token("\\/\\/.*", SExpressionSyntax.Commenting),
SExpressionSyntax.Token("false", (token, match) => false),
SExpressionSyntax.Token("true", (token, match) => true),
SExpressionSyntax.Token("null", (token, match) => null),
// Integers (unsigned)
SExpressionSyntax.Token("[0-9]+", (token, match) => int.Parse(match)),
// String literals
SExpressionSyntax.Token("\\\"(\\\\\\n|\\\\t|\\\\n|\\\\r|\\\\\\\"|[^\\\"])*\\\"", (token, match) => match.Substring(1, match.Length - 2)),
// For identifiers...
SExpressionSyntax.Token("[\\$_A-Za-z][\\$_0-9A-Za-z\\-]*", SExpressionSyntax.NewSymbol),
// ... and such
SExpressionSyntax.Token("[\\!\\&\\|\\<\\=\\>\\+\\-\\*\\/\\%\\:]+", SExpressionSyntax.NewSymbol)
);
var system = TypeSystem.Default;
var env = new Dictionary<string, IType>();
// Classic
var @bool = system.NewType(typeof(bool).Name);
var @int = system.NewType(typeof(int).Name);
var @string = system.NewType(typeof(string).Name);
// Generic list of some `item' type : List<item>
var ItemType = system.NewGeneric();
var ListType = system.NewType("List", new[] { ItemType });
// Populate the top level typing environment (aka, the language's "builtins")
env[@bool.Id] = @bool;
env[@int.Id] = @int;
env[@string.Id] = @string;
env[ListType.Id] = env["nil"] = ListType;
//...
Action<object> analyze =
(ast) =>
{
var nodes = (Node[])visitSExpr(ast);
foreach (var node in nodes)
{
try
{
Console.WriteLine();
Console.WriteLine("{0} : {1}", node.Id, system.Infer(env, node));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Console.WriteLine();
Console.WriteLine("... Done.");
};
// Parse some S-expr (in string representation)
var source =
syntax.
Parse
(@"
(
let
(
// Type inference ""playground""
// Classic..
( id ( ( x ) => x ) ) // identity
( o ( ( f g ) => ( ( x ) => ( f ( g x ) ) ) ) ) // composition
( factorial ( ( n ) => ( if ( > n 0 ) ( * n ( factorial ( - n 1 ) ) ) 1 ) ) )
// More interesting..
( fmap (
( f l ) =>
( if ( empty l )
( : ( f ( head l ) ) ( fmap f ( tail l ) ) )
nil
)
) )
// your own...
)
( )
)
");
// Visit the parsed S-expr, turn it into a more friendly AST for H-M
// (see Node, et al, above) and infer some types from the latter
analyze(source);
// ...
......产生:
id : Function<`u, `u>
o : Function<Function<`z, `aa>, Function<`y, `z>, Function<`y, `aa>>
factorial : Function<Int32, Int32>
fmap : Function<Function<`au, `ax>, List<`au>, List<`ax>>
... Done.
另请参阅bitbucket上的Brian McKenna's JavaScript implementation,这也有助于入门(为我工作)。
“HTH,