[functional-programming] Hindley-Milner는 무엇입니까?

나는이 용어 Hindley-Milner를 만났고 그것이 무엇을 의미하는지 잘 모르겠습니다.

다음 게시물을 읽었습니다.

그러나 일반적으로 간결한 설명을 제공하는 위키피디아에는이 용어에 대한 단일 항목이 없습니다.
참고이제 하나가 추가되었습니다.

뭐야?
어떤 언어와 도구가이를 구현하거나 사용합니까?
간결한 답변을 주시겠습니까?



답변

Hindley-Milner는 Roger Hindley (논리를 살펴본 사람)와 나중에 Robin Milner (프로그래밍 언어를 살펴본 사람)가 독자적으로 발견 한 유형 시스템 입니다. Hindley-Milner의 장점은 다음과 같습니다.

  • 다형성 기능을 지원 합니다. 예를 들어, 요소 유형에 관계없이 목록의 길이를 제공 할 수있는 함수 또는 트리에 저장된 키 유형과 관계없이 이진 트리 조회를 수행하는 함수가 있습니다.

  • 길이 함수의 예 에서처럼 함수 나 값은 두 개 이상의 유형을 가질 수 있습니다. “정수로의 정수 목록”, “정수로의 문자열 목록”, “정수로의 쌍 목록”등이 될 수 있습니다. 의 위에. 이 경우 Hindley-Milner 시스템의 신호 이점은 잘 유형이 지정된 각 용어가 주 유형 이라고 하는 고유 한 “최상”유형 을 갖는다는 것 입니다. 목록 길이 함수의 주요 유형은 “모든 a, 함수 목록 a에서 정수로”입니다. 여기 에 람다 미적분학 에서는 명시 적이 지만 대부분의 프로그래밍 언어 에서는 암시 적인a “유형 매개 변수”가 있습니다 .파라 메트릭 다형성 . (ML에서 길이 함수의 정의를 작성하면 다음과 같이 유형 매개 변수를 볼 수 있습니다.

     fun 'a length []      = 0
       | 'a length (x::xs) = 1 + length xs
    
  • 경우 용어가 힌들리 – 밀너 유형이, 다음 의 주요 유형은 모든 종류의 선언없이 유추 할 수있다 프로그래머 또는 다른 주석을. (주석없이 대량의 ML 코드를 처리 한 적이있는 사람은 누구나 증명할 수 있으므로 이것은 혼합 된 축복입니다.)

Hindley-Milner는 거의 모든 정적으로 형식화 된 함수 언어의 형식 시스템에 대한 기반입니다. 일반적으로 사용되는 언어는 다음과 같습니다.

이 모든 언어는 Hindley-Milner를 확장했습니다. Haskell, Clean 및 Objective Caml은 야심 차고 특이한 방식으로 그렇게합니다. (예를 들어, 기본 Hindley-Milner는 지정되지 않은 유형의 값 목록을 보유하는 가변 셀을 사용하여 전복 될 수 있으므로 가변 변수를 처리하려면 확장이 필요합니다. 이러한 문제는 값 제한 이라는 확장으로 처리 됩니다 .)

유형화 된 기능 언어를 기반으로하는 다른 많은 보조 언어와 도구는 Hindley-Milner를 사용합니다.

Hindley-Milner는 더 많은 유형을 허용하지만 프로그래머의 주석필요한 System F .


답변

Google Scholar 또는 CiteSeer 또는 지역 대학 도서관을 사용하여 원본 논문을 찾을 수 있습니다. 첫 번째는 저널의 제본 사본을 찾아야 할만큼 충분히 오래되었지만 온라인에서 찾을 수 없었습니다. 다른 하나에 대해 찾은 링크가 끊어졌지만 다른 링크가있을 수 있습니다. 이를 인용하는 논문을 확실히 찾을 수있을 것입니다.

Hindley, Roger J, 조합 논리에서 대상의 주요 유형 체계 , Transactions of the American Mathematical Society, 1969.

Milner, Robin, A Theory of Type Polymorphism , Journal of Computer and System Sciences, 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,


답변