什么是辛德雷

我遇到了这个术语Hindley-Milner,我不确定是否掌握它的意思。

我已阅读以下帖子:

  • Steve Yegge - 动态语言反击
  • Steve Yegge - 木偶奇遇记问题
  • Daniel Spiewak - 什么是Hindley-Milner? (为什么它很酷?)
  • 但是这个词在维基百科上没有单一的条目,通常给我一个简明的解释。
    - 现在已添加一个

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


    Hindley-Milner是Roger Hindley(他正在研究逻辑)和Robin Milner(他正在研究编程语言)之后独立发现的类型系统 。 Hindley-Milner的优点是

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

  • 有时一个函数或值可以有多个类型 ,如长度函数的例子:它可以是“整数列表整数”,“列表整数的字符串”,“对整数列表的列表”等等上。 在这种情况下,Hindley-Milner系统的信号优势在于每个良好类型的术语具有独特的“最佳”类型 ,称为主体类型。 列表长度函数的主要类型是“任何a ,从列表功能a为整数”。 这里的a是一个所谓的“类型参数”,它在lambda演算中显式的,在大多数编程语言中都是隐含的 。 类型参数的使用解释了为什么Hindley-Milner是一个实现参数多态的系统。 (如果您在ML中编写长度函数的定义,则可以看到类型参数:

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

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

  • ML系列(标准ML和目标Caml)
  • 哈斯克尔
  • 清洁
  • 所有这些语言都延伸了欣德利米尔纳; Haskell,Clean和Objective Caml采用雄心勃勃且不同寻常的方式。 (需要扩展来处理可变变量,因为基本的Hindley-Milner可以被颠覆,例如,一个可变单元格包含一个未指定类型的值列表,这种问题由称为值限制的扩展来处理。

    基于键入功能语言的许多其他小语言和工具使用Hindley-Milner。

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


    您可以使用Google Scholar或CiteSeer或您当地的大学图书馆查找原始论文。 第一个已经够老了,你可能不得不找到该日记的装订副本,我无法在网上找到它。 我为另一个人找到的链接被打破了,但可能还有其他链接。 你一定能找到引用这些的论文。

    Hindley,Roger J,“组合逻辑中对象的主要类型方案”,美国数学学会杂志,1969年。

    米尔纳,罗宾,一种类型多态性理论,计算机与系统科学学报,1978年。


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

    (Lisp-ish)S表达式中的Hindley-Milner类型推断,在650行以下的C#

    请注意,实现仅在C#的270行左右的范围内(对于算法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.
    

    另请参阅Brian McKenna在bitbucket上的JavaScript实现,这也有助于开始(为我工作)。

    “HTH,

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

    上一篇: What is Hindley

    下一篇: Why hasn't functional programming taken over yet?