O que é Hindley-Milner?
-
29-08-2019 - |
Pergunta
Eu encontrei este termo Hindley-Milner , e eu não estou certo se entender o que isso significa.
Eu li as seguintes mensagens:
- Steve Yegge - Linguagens Dinâmicas Strike Back
- Steve Yegge - O Pinocchio Problema
- Daniel Spiewak - que é Hindley-Milner? (E por que é legal?)
Mas não há nenhuma entrada única para este termo na Wikipedia onde normalmente me oferece uma explicação concisa.
Nota ??strong> - um tem agora foi adicionado
O que é isso?
Que linguagens e ferramentas de implementação ou usá-lo?
Você poderia por favor oferecer uma resposta concisa?
Solução
Hindley-Milner é um sistema de tipo descoberto independentemente por Roger Hindley (que estava olhando para a lógica) e mais tarde por Robin Milner (que estava olhando para as linguagens de programação). As vantagens de Hindley-Milner são
-
Ele suporta polimórfica funções; por exemplo, uma função que pode lhe dar o comprimento da lista independente do tipo de elementos, ou uma função faz um binário-árvore de pesquisa independente do tipo de chaves armazenadas na árvore.
-
Às vezes, uma função ou valor pode ter mais de um tipo , como no exemplo da função comprimento: pode ser "lista de inteiros para inteiro", "lista de strings para integer", 'lista de pares para inteiro', e assim por diante. Neste caso, uma vantagem de sinal do sistema de Hindley-Milner é que cada termo bem tipado tem um "melhor" tipo único , que é chamado de tipo principais . O principal tipo de função a lista de comprimento é "para qualquer
a
, função da lista dea
ao número inteiro". Aquia
é um chamado "parâmetro do tipo", que é explícito no lambda calculus e implícita na maioria das linguagens de programação . O uso de parâmetros de tipo explica por Hindley-Milner é um sistema que implementa paramétrico polimorfismo . (Se você escrever uma definição da função de comprimento no ML, você pode ver o parâmetro de tipo assim:fun 'a length [] = 0 | 'a length (x::xs) = 1 + length xs
-
Se um termo tem um tipo de Hindley-Milner, em seguida, o tipo de capital pode ser inferida sem exigir quaisquer declarações de tipo ou outras anotações pelo programador. (Esta é uma faca de dois gumes, como qualquer um pode atestar que já tenha sido tratado um grande pedaço de código ML sem anotações.)
Hindley-Milner é a base para o sistema de tipo de quase todas as línguas funcional de tipagem estática. Tais linguagens de uso comum incluem
- A família ML ( ML padrão e Objective Caml )
- Haskell
- Limpo
Todas as línguas têm estendido Hindley-Milner; Haskell, Clean, and Objective Caml fazê-lo de forma ambiciosas e incomuns. (Extensões são necessárias para lidar com variáveis ??mutáveis, desde básica Hindley-Milner pode ser subvertida utilizando, por exemplo, uma célula mutável segurando uma lista de valores de tipo não especificado. Tais problemas são tratados por uma extensão chamada de restrição de valor .)
Muitas outras línguas menores e ferramentas baseadas em linguagens funcionais digitadas usar Hindley-Milner.
Hindley-Milner é uma restrição do Sistema F , que permite mais tipos, mas que requer anotações pelo programador .
Outras dicas
Você pode ser capaz de encontrar os documentos originais usando Google Scholar ou CiteSeer - ou a sua biblioteca da universidade local. O primeiro é o suficiente velho que você pode ter que encontrar cópias encadernadas da revista, eu não poderia encontrá-lo online. O link que eu encontrei para o outro foi quebrado, mas pode haver outros. Você certamente vai ser capaz de encontrar artigos que citam estes.
Hindley, Roger J, O principal esquema de tipo de um objeto na lógica combinatória , Transações da American Mathematical Society de 1969.
Milner, Robin, A Theory of Type Polimorfismo , Jornal de computador eo sistema Ciências de 1978.
Simples Hindley-Milner implementação inferência de tipos em C #:
Hindley-Milner tipo inferência sobre (Lisp-ish) S-expressões, em menos de 650 linhas de C #
a execução é na gama de apenas 270 ou menos linhas de C # (W para o algoritmo adequado e as poucas estruturas de dados para o suportam, pelo menos).
Uso trecho:
// ...
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);
// ...
... que produz:
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.
Veja também implementação JavaScript do Brian McKenna em bitbucket, o que também ajuda a obter iniciado (trabalhou para mim).
'HTH,