Що таке Хіндлі-Мілнер?


124

Я стикався з цим терміном Хіндлі-Мілнер , і я не впевнений, чи розумію, що це означає.

Я читав наступні публікації:

Але немає жодного запису для цього терміна у вікіпедії, де зазвичай мені пропонують стисле пояснення.
Примітка. Один зараз додано

Що це?
Які мови та інструменти його реалізують чи використовують?
Чи запропонуєте, будь ласка, стислу відповідь?

Відповіді:


167

Хіндлі-Мілнер - система типів, відкрита незалежно Роджером Хіндлі (який дивився на логіку), а згодом Робіном Мілнером (який дивився на мови програмування). Переваги Хіндлі-Мілнера є

  • Він підтримує поліморфні функції; наприклад, функція, яка може надати вам довжину списку незалежно від типу елементів, або функція здійснює пошук бінарних дерев незалежно від типу ключів, що зберігаються в дереві.

  • Іноді функція або значення може мати більше одного типу , як у прикладі функції довжини: це може бути "список цілих чисел до цілого числа", "список рядків до цілого числа", "список пар до цілого числа" і так далі на. У цьому випадку перевагою сигналу системи Гіндлі-Мілнера є те, що кожен добре набраний термін має унікальний тип "кращий" , який називається основним типом . Основним типом функції довжини списку є "для будь-якої a, функції від списку aдо цілого". Ось aтак званий "параметр типу", який явний в лямбдальному обчисленні, але неявний у більшості мов програмування .параметричний поліморфізм . (Якщо ви пишете визначення функції довжини в ML, ви можете бачити параметр типу таким чином:

     fun 'a length []      = 0
       | 'a length (x::xs) = 1 + length xs
    
  • Якщо термін має тип Хіндлі-Мілнера, то основний тип можна зробити, не вимагаючи жодних декларацій типу або інших анотацій програмістом. (Це змішане благо, оскільки кожен може засвідчити, хто коли-небудь обробляв великий шматок коду ML без анотацій.)

Хіндлі-Мілнер є основою для типової системи майже кожної статично типованої функціональної мови. До таких мов у загальному користуванні належать:

Усі ці мови поширили Гіндлі-Мілнер; Haskell, Clean і Objective Caml роблять це амбітними та незвичними способами. (Розширення потрібні для роботи зі змінними змінними, оскільки основні Hindley-Milner можна підривати, використовуючи, наприклад, змінну комірку, що містить список значень неуточненого типу. Такі проблеми вирішуються розширенням, званим обмеженням значення .)

Багато інших другорядних мов та інструментів, заснованих на набраних функціональних мовах, використовують Hindley-Milner.

Hindley-Milner - це обмеження системи F , яке дозволяє більше типів, але для цього потрібні анотації програміста .


2
@NormanRamsey Я знаю, що це стареньке зло, але дякую, що вияснили те, що нескінченно мене дратувало: Кожен раз, коли я посилаюсь на систему типу hindley-milner, хтось звучить, коли говорити про висновки типу до того, що я почав запитати, чи є HM типом система або просто алгоритм висновку ... Дякую за те, що я маю на увазі вікіпедію для дезінформування людей про це до того, що вони мене навіть збентежили ..
Джиммі Хоффа

1
Чому він параметрично поліморфний, на відміну від просто поліморфного? Приклад із програмою «Будь-який ви надали», я бачу це як приклад поліморфізму - де підтипи можуть використовуватися замість супертипу, визначеного у визначенні, а не параметричного поліморфізму ala C ++, де фактичний тип задається програмістом для створення нова функція.
corazza

1
@jcora: Кілька років пізно, але в інтересах читачів майбутнього: це називається параметричним поліморфізмом завдяки властивості parametricity , що кошти для будь-якого типу ви підключаєте, всі екземпляри функції , як length :: forall a. [a] -> Intповинні вести себе однаково , незалежно від a-Це непрозорий; ти нічого не знаєш про це. Немає жодної instanceof(Java-дженерики) ні "набору качок" (шаблони C ++), якщо ви не додасте додаткові обмеження типу (типи класів Haskell). Завдяки параметричності ви можете отримати хороші докази того, що саме функція може / не може виконувати.
Джон Перді

8

Ви можете знайти оригінальні документи за допомогою Google Scholar або CiteSeer - або у вашій місцевій університетській бібліотеці. Перший досить старий, що вам, можливо, доведеться знайти примірники журналу, я не зміг його знайти в Інтернеті. Посилання, яке я знайшов для іншого, було розірвано, але можуть бути й інші. Ви, безумовно, зможете знайти документи, які цитують їх.

Хіндлі, Роджер Дж., Основна типова схема об'єкта в комбінаційній логіці , трансакції Американського математичного товариства, 1969.

Мілнер, Робін, Теорія поліморфізму типу , Журнал комп'ютерних та системних наук, 1978.


2
Останню можна знайти тут: citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.67.5276
Магнус


6

Проста реалізація виводу типу Hindley-Milner в C #:

Hindley-Milner типу висновок над (Lisp-ish) S-виразами, під 650 рядками C #

Зауважте, реалізація знаходиться в діапазоні лише 270 рядків C # (для власне алгоритму 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.

Дивіться також реалізацію JavaScript Брайана Маккенни на бітбукеті, що також допомагає розпочати роботу (для мене).

'HTH,

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.