[РЕДАКТУЙТЕ: Вуалюйте кілька слів на кожному]
Існує кілька способів розширення умовиводу типу HM. Моя відповідь ґрунтується на багатьох, більш-менш успішних спробах реалізації деяких з них. Перший, на який я натрапив, - це параметричний поліморфізм . Системи типів, які намагаються поширити HM в цьому напрямку, схиляються до системи F і тому вимагають анотацій типу. Два помітних розширень у цьому напрямку, на які я натрапив, є:
HMF, він дозволяє зробити висновок про типи для всіх типів System-F, а це означає, що ви можете мати універсальне кількісне визначення "в середині" типу, їх поява неявно не розташоване на найвищому обсязі, як для поліморфних типів HM. У документі чітко зазначено, що не існує чіткого правила щодо того, скільки та де тип приміток може знадобитися. Також типи, що належать до системи F, терміни зазвичай не мають головного типу.
MLF - це не лише розширення HM, це також розширення системи F, яка повертає властивість основного типу HM шляхом введення свого роду обмеженого кількісного визначення за типами. Авторами було проведено порівняння, MLF суворо потужніший, ніж HMF, а примітки потрібні лише для параметрів, які використовуються поліморфно.
Інший спосіб розширення HM - через зміну області обмеження.
HM (X) - параметр Гіндлі-Мілнера, що параметризується над областю обмеження X. У цьому підході алгоритм HM генерує обмеження, які надсилаються до вирішувача домену для X. Для звичайного HM вирішувач домену - це процедура об'єднання, і домен складається набору строків, побудованих із типів та змінних типів.
Іншим прикладом для X можуть бути обмеження, виражені мовою арифметики Пребургера (у цьому випадку виведення / перевірка типу вирішується) або мовою арифметики Пеано (більше не можна визначити). X змінюється в різних спектрах теорій, кожна з яких має власні вимоги щодо кількості та локалізації необхідних анотацій типу та починає від них зовсім не до всіх.
Класи типів Haskell також є своєрідним розширенням домену обмеження шляхом додавання предикатів типу форми MyClass(MyType)
(означає, що існує екземпляр MyClass для типу MyType).
Класи типів зберігають умовивід типу, оскільки вони є в основному (майже) ортогональними поняттями, в яких реалізується адмоковий поліморфізм .
В якості прикладу візьмемо символ val
типу , val :: MyClass a => a
для яких ви можете мати примірників MyClass A
, і MyClass B
т.д. Якщо ви посилаєтеся на цей символ в коді, насправді це тому , що визначення типу вже виконується , що компілятор може зробити висновок , який екземпляр класу використання. Це означає, що типval
залежить від контексту, в якому він використовується. Ось чому також запуск однієї val
операції призводить доambiguous type error
: компілятор не може зробити висновок будь-якого типу на основі контексту.
Для більш досконалих систем типу, таких як GADT, сім'ї типів, залежні типи, System (F) ω тощо, тип вже не є "типами", вони стають складними обчислювальними об'єктами. Наприклад, це означає, що два типи, які не виглядають однаково, необов'язково відрізняються. Отже рівність типу стає зовсім не тривіальною (взагалі).
Щоб навести приклад фактичної складності, розглянемо залежний тип списку: NList a n
де a
тип об’єктів у списку та n
його довжина.
Функція додавання мала б тип append :: NList a n -> NList a m -> NList a (n + m)
і функція zip була б zip :: NList a n -> NList b n -> NList (a, b) n
.
Уявіть, тепер у нас лямбда \a: NList t n, b: NList t m -> zip (append a b) (append b a)
. Тут перший аргумент zip має тип, NList t (n + m)
а другий - тип NList t (m + n)
.
Майже те саме, але якщо перевіряючий тип не знає, що "+" комутується на натуральних числах, він повинен відхилити функцію, оскільки (n + m) не є буквально (m + n). Йдеться вже не про висновок типу / перевірку типу, це про доведення теореми.
Рідкі типи, здається, роблять деякі залежні умовиводи. Але, як я розумію, це насправді не залежний тип, а щось подібне до звичайних типів HM, для яких робиться додатковий висновок для обчислення статичних меж.
Я сподіваюся, що це допомагає.