РЕДАКТУВАННЯ: Коментований вище коментар надав відсутній фрагмент. Деякі люди свідомо грають з менш мовними, ніж повний мов. Я явно не переймаюся такими мовами. По-справжньому корисною мовою, що не вимагає повного твердження, є шалено складна річ. Вся інша частина цього розширюється на те, що відбувається, намагаючись застосувати ці теореми до повної мови.
Помилковий!
function f(a): forall t: Type, t->t
function g(a): forall t: Type, t->t
return (a is g) ? f : a
return a is f ? g : a
де is
оператор порівнює дві змінні для еталонної ідентичності. Тобто вони містять однакове значення. Не еквівалентне значення, однакове значення. Функції f
та g
еквівалентні за деяким визначенням, але вони не однакові.
Якщо ця функція передана сама, вона повертає щось інше; інакше він повертає свій вклад. Щось інше має той самий тип, що і саме його, тому його можна замінити. Іншими словами, f
це не тотожність, тому що f(f)
повертається g
, тоді як ідентичність повертається f
.
Щоб теорема була дотримана, вона повинна припускати смішну здатність до скорочення
function cantor(n, <z, a>) : forall t: t: Type int, <int, t> -> <int, t>
return n > 1 ? cantor((n % 2 > 0) ? (n + 1) : n / 2, <z + 1, a>) : <z, a>
return cantor(1000, <0, a>)[1]¹
Якщо ви готові припустити, що ви можете припустити, що набагато простіше можна зробити висновок про тип.
Якщо ми спробуємо обмежити область до тих пір, поки теорема не витримає, ми зрештою повинні обмежити її жахливо.
- Чистий функціонал (без змінного стану, без IO). Гаразд, я можу з цим жити. Багато часу ми хочемо виконувати докази над функціями.
- Порожня стандартна бібліотека. мех.
- Ні
raise
і ні exit
. Тепер ми починаємо обмежуватися.
- Нижнього типу немає.
- У мові є правило, яке дозволяє компілятору згортати нескінченну рекурсію, вважаючи, що вона повинна припинитися. Компілятору дозволено відкидати тривіальну нескінченну рекурсію.
- Компілятор може відмовити, якщо представлений щось, що не може бути доведено жодним чином .² Тепер стандартна бібліотека не може приймати функції як аргументи. Бу
- Немає
nil
. Це починає ставати проблематичним. У нас не вистачає способів боротьби з 1/100
- Мова не може робити умовиводи філіальної форми та не може переосмислити те, коли програміст може довести висновок типу, що не може бути. Це досить погано.
Існування обох останніх двох обмежень скорило мову. Хоча досі Тюрінг є повним, єдиний спосіб вирішити загальну мету - це імітувати внутрішню платформу, що інтерпретує мову із втраченими вимогами.
¹ Якщо ви думаєте, що компілятор може вивести цей, спробуйте цей
function fermat(z) : int -> int
function pow(x, p)
return p = 0 ? 1 : x * pow(x, p - 1)
function f2(x, y, z) : int, int, int -> <int, int>
left = pow(x, 5) + pow(y, 5)
right = pow(z, 5)
return left = right
? <x, y>
: pow(x, 5) < right
? f2(x + 1, y, z)
: pow(y, 5) < right
? f2(2, y + 1, z)
: f2(2, 2, z + 1)
return f2(2, 2, z)
function cantor(n, <z, a>) : forall t: t: Type int, <int, t> -> <int, t>
return n > 1 ? cantor((n % 2 > 0) ? (n + 1) : n / 2, <z + 1, a>) : <z, a>
return cantor(fermat(3)[0], <0, a>)[1]
² Доказ того, що компілятор не може цього зробити, залежить від осліплення. Ми можемо використовувати кілька бібліотек, щоб переконатися, що компілятор не може побачити цикл відразу. Крім того, ми завжди можемо щось побудувати там, де програма працюватиме, але не може бути складена, оскільки компілятор не може виконати індукцію у доступній пам'яті.
³ Хтось вважає, що ви можете мати цей зворотний нуль без довільних загальних типів, що повертають нуль. Це платить жахливий штраф, за який я не бачив жодної ефективної мови, яка могла б його заплатити.
function f(a, b, c): t: Type: t[],int,int->t
return a[b/c]
не повинен компілювати. Основна проблема полягає в тому, що індексація масиву виконання не працює більше.