Я трохи подумав про це. Основне питання полягає в тому, що загалом ми не знаємо, наскільки велике значення має поліморфний тип. Якщо у вас немає цієї інформації, вам доведеться якось її отримувати. Мономорфізація отримує цю інформацію для вас, спеціалізуючись на поліморфізмі. Бокс отримує цю інформацію для вас, ставлячи все в подання відомого розміру.
Третя альтернатива - відстежувати цю інформацію у видах. В основному, ви можете ввести різний вид для кожного розміру даних, і тоді поліморфні функції можна визначити для всіх типів певного розміру. Я намалюю таку систему нижче.
ВидиТип конструкторівκА: : = П: : =|∀ a : κ .А|α|A × B|A + B|А → Вr e fА|П а д ( к )|μ α : κ .А
Тут ідея високого рівня полягає в тому, що тип типу говорить вам, скільки слів потрібно, щоб викласти об’єкт в пам'ять. Для будь-якого заданого розміру легко бути поліморфним над усіма типами саме цього розміру. Оскільки кожен тип - навіть поліморфний - все ще має відомий розмір, компіляція не є більш важкою, ніж для C.
Правила впорядкування перетворюють цю англійську мову на математику і повинні виглядати приблизно так:
Γ ⊢ A : n Γ ⊢ B : m
α : n ∈ ΓΓ ⊢ α : nΓ , α : n ⊢ A : mΓ ⊢ ∀ α : n .A : m
Γ ⊢ A : m Γ ⊢ B : nΓ ⊢ A : nΓ ⊢ В : мΓ ⊢ A × B : n + mΓ ⊢ A : nΓ ⊢ B : nΓ ⊢ A + B : n + 1
Γ ⊢ А : мΓ ⊢ B : nΓ ⊢ A → B : 1Γ ⊢ A : nΓ ⊢ r e fA : 1
Γ ⊢ P a d ( k ) : kΓ , α : n ⊢ A : nΓ ⊢ μ α : n .A : n
Таким чином, кількісний коефіцієнт вимагає, щоб ви наділяли тип, на який ви перебуваєте. Аналогічно, спарювання - це незміщений тип пари, який просто розміщує поряд із в пам'яті (як тип структури C). Нерозчленовані спілки беруть два значення однакового розміру, а потім додають слово для тега-дискримінатора. Функції - це закриття, представлені, як зазвичай, вказівником на запис середовища та коду.A × BАБ
Посилання цікаві - вказівники - це завжди одне слово, але вони можуть вказувати на значення будь-якого розміру. Це дозволяє програмістам реалізувати
поліморфізм до довільних об'єктів шляхом боксу, але не вимагає від
них цього. Нарешті, коли явні розміри граються, часто корисно вводити тип прокладки, який використовує простір, але нічого не робить. (Отже, якщо ви хочете взяти роз'єднаний об'єднання int і пари int, вам потрібно буде додати прокладку першого int, щоб макет об'єкта був рівномірним.)
Рекурсивні типи мають стандартне правило формування, але зауважте, що рекурсивні випадки мають бути однакового розміру, а це означає, що вам зазвичай доводиться вставляти їх у вказівник, щоб узагальнити роботу. Наприклад, тип даних списку може бути представлений як
μ α : 1.r e f( P a d ( 2 ) + i n t × α )
Таким чином, це вказує на значення порожнього списку, або пару int та покажчик на інший пов'язаний список.
Перевірка типу для таких систем також не дуже складна; алгоритм у моєму документі ICFP з Джошуа Данфілдом, Повна та проста двонаправлена перевірка типу для поліморфізму вищого рангу застосовується до цього випадку майже без змін.