답변:
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 .
length :: forall a. [a] -> Int
에 관계없이 동일하게 동작합니다 a
- 그것은의 불투명체; 당신은 그것에 대해 아무것도 모릅니다. 전혀 없습니다 instanceof
(자바 제네릭)도 "오리 입력"(C ++ 템플릿)을 추가 형 제약 (하스켈 typeclasses)을 추가하지 않는 한이. 매개 변수를 사용하면 함수가 할 수있는 작업과 할 수없는 작업에 대한 좋은 증거를 얻을 수 있습니다.
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,