回答:
Hindley-Milnerは、(ロジックを検討していた)Roger Hindleyが独自に発見し、後に(プログラミング言語を検討していた)Robin Milnerが独自に発見した型システムです。Hindley-Milnerの利点は
多態性関数をサポートしています。たとえば、要素のタイプに関係なくリストの長さを提供できる関数、または関数は、ツリーに格納されているキーのタイプに関係なくバイナリツリールックアップを実行します。
関数または値は、長さ関数の例のように、複数のタイプを持つことができます。「整数から整数へのリスト」、「文字列から整数へのリスト」、「ペアから整数へのリスト」などの場合があります。オン。この場合、Hindley-Milnerシステムのシグナルの利点は、適切に型付けされた各用語に、「プリンシパルタイプ」と呼ばれる一意の「最良の」タイプがあることです。list-length関数の主なタイプは、「for for a
、リストa
から整数への関数」です。ここa
では、いわゆる「typeパラメータ、」あるラムダ計算で明示的になく、ほとんどのプログラミング言語での暗黙のは。パラメトリックポリモーフィズム。(MLで長さ関数の定義を記述すると、typeパラメータを次のように表示できます。
fun 'a length [] = 0
| 'a length (x::xs) = 1 + length xs
用語にHindley-Milner型がある場合、プログラマーによる型宣言やその他の注釈を必要とせずに、プリンシパル型を推測できます。(これは混合された祝福です。誰もアノテーションなしで大量のMLコードを処理したことがある人なら誰でも証明できるからです。)
Hindley-Milnerは、ほとんどすべての静的型付けされた関数型言語の型システムの基礎です。一般的に使用されるそのような言語には、
これらの言語はすべてHindley-Milnerを拡張しています。Haskell、Clean、およびObjective Camlは、野心的で珍しい方法でこれを行います。(たとえば、基本的なHindley-Milnerは、指定されていない型の値のリストを保持する可変セルを使用して破壊できるため、拡張機能は可変変数を処理するために必要です。このような問題は、値制限と呼ばれる拡張機能によって処理されます。)
型付き関数型言語に基づく他の多くのマイナー言語とツールはHindley-Milnerを使用しています。
Hindley-MilnerはSystem Fの制限であり、より多くの型を使用できますが、プログラマーによる注釈が必要です。
length :: forall a. [a] -> Int
にかかわらず同じように動作しなければならないa
-itさん不透明; あなたはそれについて何も知りません。instanceof
追加の型制約(Haskell型クラス)を追加しない限り、(Javaジェネリック)も「ダックタイピング」(C ++テンプレート)もありません。パラメトリック性を使用すると、関数が実行できる/できないことを正確に証明できます。
Google Scholar、CiteSeer、または地元の大学図書館を使用して、元の論文を見つけることができる場合があります。1つ目は、雑誌の製本を見つけなければならないほど古く、オンラインでは見つけられませんでした。もう片方で見つけたリンクは壊れていましたが、他にあるかもしれません。あなたは確かにこれらを引用する論文を見つけることができるでしょう。
Hindley、Roger J、組み合わせ論理におけるオブジェクトの主要な型スキーム、アメリカ数学会のトランザクション、1969年。
ミルナー、ロビン、タイプ多型の理論、コンピュータとシステム科学のジャーナル、1978年。
C#での単純なHindley-Milner型推論の実装:
(Lispっぽい)S式に対するHindley-Milner型の推論、C#の650行未満
実装は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、