什么是Hindley-Milner?

yeh*_*nan 121 types functional-programming inference hindley-milner

我遇到了这个术语Hindley-Milner,我不确定是否掌握了它的含义.

我看过以下帖子:

但是维基百科中没有单一的条目,通常会给我一个简明的解释.
注意 - 现在添加了一个

它是什么?
哪些语言和工具实现或使用它?
你能提供一个简明的答案吗?

Nor*_*sey 163

Hindley-Milner是由Roger Hindley独立发现的类型系统(他正在研究逻辑),后来由Robin Milner(正在研究编程语言)发现.Hindley-Milner的优势在于

  • 它支持多态函数; 例如,一个函数可以为您提供独立于元素类型的列表长度,或者函数执行二叉树查找,而不依赖于树中存储的键的类型.

  • 有时函数或值可以有多个类型,如长度函数的示例:它可以是"整数列表整数","字符串列表整数","对列表整数"等等上.在这种情况下,Hindley-Milner系统的信号优势在于每个良好类型的术语都具有唯一的"最佳"类型,称为主要类型.list-length函数的主要类型是"for any a,function from list of ainteger".这a是一个所谓的"类型参数",它在lambda演算中显式的,在大多数编程语言中是隐含的.参数多态性.(如果在ML中编写长度函数的定义,则可以看到类型参数:

     fun 'a length []      = 0
       | 'a length (x::xs) = 1 + length xs
    
    Run Code Online (Sandbox Code Playgroud)
  • 如果一个术语具有Hindley-Milner类型,则可以推断出主体类型,而不需要程序员进行任何类型声明或其他注释.(这是一种喜忧参半的祝福,因为任何人都可以证明曾经处理过大量没有注释的ML代码.)

Hindley-Milner是几乎所有静态类型函数式语言类型系统的基础.常用的这类语言包括

所有这些语言都扩展了Hindley-Milner; Haskell,Clean和Objective Caml以雄心勃勃和不寻常的方式这样做.(需要扩展来处理可变变量,因为基本的Hindley-Milner可以使用例如包含未指定类型的值列表的可变单元来破坏.这些问题由称为值限制的扩展来处理.)

许多其他基于类型化函数语言的次要语言和工具使用Hindley-Milner.

Hindley-Milner是System F的限制,它允许更多类型但需要程序员注释.

  • @NormanRamsey我知道这很糟糕,但是感谢您清理无休止地困扰我的事情:每当我提到印度斯坦-米尔纳类型系统时,都会有人在谈论类型推断时大声疾呼,以至于我开始质疑HM是否是类型系统或只是推理算法...谢谢,我想让Wikipedia误导人们这一点,甚至使我感到困惑。 (2认同)
  • @jcora:晚了几年,但为了未来读者的利益:由于[parametricity](https://en.wikipedia.org/wiki/Parametricity)的属性,它被称为*参数*多态性,这意味着对于任何输入您插入的函数的所有实例,例如“length :: forall a”。[a] -> Int` 必须表现相同,无论 `a` 是什么——它是不透明的;你对此一无所知。除非添加额外的类型约束(Haskell 类型类),否则没有“instanceof”(Java 泛型)或“鸭子类型”(C++ 模板)。通过参数化,您可以获得一些关于函数可以/不能做什么的很好的证明。 (2认同)

tva*_*son 8

您可以使用Google学术搜索或CiteSeer或您当地的大学图书馆查找原始论文.第一个是足够大,你可能必须找到期刊的绑定副本,我无法在网上找到它.我找到的另一个链接被打破了,但可能还有其他链接.你当然能找到引用这些的论文.

Hindley,Roger J,"组合逻辑中对象的主要类型方案","美国数学学会交易",1969年.

Milner,Robin,A型多态性,计算机与系统科学,1978.

  • 后者可以在这里找到:http://citeseerx.ist.psu.edu/viewdoc/summary?doi = 10.1.1.67.5276 (2认同)
  • 前者:http://www.ams.org/journals/tran/1969-146-00/S0002-9947-1969-0253905-6/S0002-9947-1969-0253905-6.pdf (2认同)

YSh*_*arp 5

C#中简单的Hindley-Milner类推理实现:

Hindley-Milner类型推断(Lisp-ish)S表达式,在650行以下的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);

    // ...
Run Code Online (Sandbox Code Playgroud)

...产生:

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.
Run Code Online (Sandbox Code Playgroud)

另请参阅Brian McKenna关于bitbucket 的JavaScript实现,这也有助于入门(为我工作).

"HTH,