Поліморфізм вищого рангу по відношенню до незмінених типів


10

У мене є мова, в якій типи за замовчуванням нерозкриваються, з виведенням типу на основі Гіндлі – Мілнера. Я хотів би додати поліморфізм вищого рангу, головним чином для роботи з екзистенційними типами.

Думаю, я розумію, як перевірити ці типи, але я не впевнений, що робити при складанні. В даний час я компілюю поліморфні визначення, генеруючи спеціалізації, подібно до шаблонів C ++, щоб вони могли працювати з неосмисленими значеннями. Наприклад, з даним визначенням f<T>, якщо програма посилається лише на f<Int32>і f<Char>, то у складеній програмі відображаються лише ті спеціалізації. (Я зараз припускаю складання цілої програми.)

Але, передаючи поліморфну ​​функцію як аргумент, я не бачу, як я можу статично генерувати правильну спеціалізацію, оскільки функція може бути обрана під час виконання. У мене немає іншого вибору, як використовувати подання в коробці? Або є спосіб вирішити це питання?

Моя перша думка була якоюсь - то чином закодувати rank- н поліморфізм , як 1 -го рангу, але я не вірю , що це можливо в цілому , так як формула конструктивної логіки не обов'язково мати пренексную нормальну форму.


Альтернативою є зменшення кількості боксу, необхідного для зберігання растрових зображень, на які аргументи функції та слова в пам'яті є покажчиками. Тоді поліморфна функція / структура є фактично поліморфною над покажчиком або довільним словом даних, і структури можуть зберігати своє останнє поле (навіть якщо це поліморфне) в рядку. Ці растрові карти також можуть використовуватися в GC, щоб уникнути необхідності тегів для нетипових типів.
fread2281

@ fread2281: Насправді я робив щось подібне у більш старій версії мови. В даний час я не генерую теги для не сумарних типів, і немає GC. Я думаю, що це також сумісно з підходом Ніла К.
Джон Перді

Відповіді:


6

Я трохи подумав про це. Основне питання полягає в тому, що загалом ми не знаємо, наскільки велике значення має поліморфний тип. Якщо у вас немає цієї інформації, вам доведеться якось її отримувати. Мономорфізація отримує цю інформацію для вас, спеціалізуючись на поліморфізмі. Бокс отримує цю інформацію для вас, ставлячи все в подання відомого розміру.

Третя альтернатива - відстежувати цю інформацію у видах. В основному, ви можете ввести різний вид для кожного розміру даних, і тоді поліморфні функції можна визначити для всіх типів певного розміру. Я намалюю таку систему нижче.

Видиκ:: =нТип конструкторівА:: =а:κ.А|α|А×Б|А+Б|АБ|rеfА|Паг(к)|мкα:κ.А

Тут ідея високого рівня полягає в тому, що тип типу говорить вам, скільки слів потрібно, щоб викласти об’єкт в пам'ять. Для будь-якого заданого розміру легко бути поліморфним над усіма типами саме цього розміру. Оскільки кожен тип - навіть поліморфний - все ще має відомий розмір, компіляція не є більш важкою, ніж для C.

Правила впорядкування перетворюють цю англійську мову на математику і повинні виглядати приблизно так: ΓA : n ΓB : m

α:нΓΓα:нΓ,α:нА:мΓα:н.А:м
ΓA : m ΓB : n
ΓА:нΓБ:мΓА×Б:н+мΓА:нΓБ:нΓА+Б:н+1
ΓА:мΓБ:нΓАБ:1ΓА:нΓrеfА:1
ΓПаг(к):кΓ,α:нА:нΓмкα:н.А:н

Таким чином, кількісний коефіцієнт вимагає, щоб ви наділяли тип, на який ви перебуваєте. Аналогічно, спарювання - це незміщений тип пари, який просто розміщує поряд із в пам'яті (як тип структури C). Нерозчленовані спілки беруть два значення однакового розміру, а потім додають слово для тега-дискримінатора. Функції - це закриття, представлені, як зазвичай, вказівником на запис середовища та коду.А×БАБ

Посилання цікаві - вказівники - це завжди одне слово, але вони можуть вказувати на значення будь-якого розміру. Це дозволяє програмістам реалізувати поліморфізм до довільних об'єктів шляхом боксу, але не вимагає від них цього. Нарешті, коли явні розміри граються, часто корисно вводити тип прокладки, який використовує простір, але нічого не робить. (Отже, якщо ви хочете взяти роз'єднаний об'єднання int і пари int, вам потрібно буде додати прокладку першого int, щоб макет об'єкта був рівномірним.)

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

мкα:1.rеf(Паг(2)+iнт×α)

Таким чином, це вказує на значення порожнього списку, або пару int та покажчик на інший пов'язаний список.

Перевірка типу для таких систем також не дуже складна; алгоритм у моєму документі ICFP з Джошуа Данфілдом, Повна та проста двонаправлена ​​перевірка типу для поліморфізму вищого рангу застосовується до цього випадку майже без змін.


Класно, я думаю, що це акуратно стосується мого випадку використання. Мені було відомо про використання видів для міркування про представлення цінностей (наприклад, *проти GHC #), але не думав робити це таким чином. Здається розумним обмежити кількісні показники вищого рейтингу до типів відомого розміру, і я думаю, що це також дозволило б мені генерувати спеціалізації за розміром статично, не потрібно знати фактичний тип. Тепер час перечитати цей документ. :)
Джон Перді

1

Здається, це ближче до проблеми компіляції, ніж до проблеми "теоретичної інформатики", тож вам, мабуть, краще запитати в іншому місці.

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

Наприклад, представлення низькорівневих аргументів на низькому рівні зазвичай може бути класифіковано на дуже мало альтернативних варіантів, наприклад, цілочисельне або подібне, плаваюча точка чи покажчик. Тому для функції f<T>, можливо, вам справді потрібно лише генерувати 3 різні некомплектні реалізації, і ви можете представити поліморфну ​​як набір цих 3 функцій, тому інстанціювання T до Int32 - це просто вибір першого елемента кортежу, ...


Спасибі за вашу допомогу. Я не був дуже впевнений, куди його запитати, оскільки компілятор перебуває від теорії високого рівня до інженерно-технічного рівня, але я вважав, що люди тут мають деякі ідеї. Схоже, бокс тут справді може бути найбільш гнучким підходом. Прочитавши вашу відповідь і поміркувавши над нею, єдине інше розумне рішення, яке мені вдалося придумати, - це відмовитися від певної гнучкості та вимагати статичного поліморфного аргументу, наприклад, передаючи їх як самі параметри типу. Це компроміси аж донизу. : P
Джон Перді

4
Питання ОП містить цілком справедливі проблеми ТКС, як, наприклад, робити висновок щодо типу, коли Дамас-Хіндлі-Мілнер поширюється на типи вищого рангу. В цілому поліморфізм 2-го рангу має вирішальне значення для виводу, але для рангу k> 2 умовивід не можна визначити. Чи змінює це обмеження Дамас-Хіндлі-Мілнер, я не знаю. Нарешті, майже все, що роблять сучасні компілятори, повинно бути частиною TCS, але зазвичай це не тому, що виконавці компіляторів випереджають теоретиків.
Мартін Бергер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.