Чому писати компілятор функціональною мовою простіше? [зачинено]


88

Я довго думав над цим питанням, але насправді не міг знайти відповіді в Google, а також подібне питання на Stackoverflow. Якщо є дублікат, вибачте за це.

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

Це правда? А якщо так, то чому так ефективно та легко писати їх функціональними мовами, а не імперативною мовою, як C? Крім того - хіба мовний інструмент у функціональній мові не повільніший, ніж у деяких мовах низького рівня, таких як C?


5
Я б не сказав, що це простіше. Але функціональний характер складання таких завдань, як синтаксичний розбір, можливо, цілком природним чином піддається функціональному програмуванню. Функціональні мови, такі як OCaml, можуть бути надзвичайно швидкими, конкуруючи зі швидкістю C.
Роберт Харві,

17
Люди, це справді аргументовано? Напевно хтось має якесь розуміння. Я хотів би знати себе.
Роберт Харві,

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

12
Чи справді аргументовано визнавати, що деякі ніші більше підходять до певного стилю мови? "Чому C краще, ніж Javascript для написання драйверів пристроїв", я б не думав ...
CA McCann

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

Відповіді:


101

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

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


Наразі найповніша відповідь, я позначу це як прийняту відповідь, проте я думаю, що відповідь Піта Кіркхема також хороша.
wvd

1
Що стосується "забезпечення коректності", оскільки коректність компілятора є важливим атрибутом, я часто чув, що шанувальники функціональних мов якось включають "доказ" правильності у свій робочий процес. Я поняття не маю, що це насправді означає на практиці, але оскільки надійність компілятора важлива, це видається вартим.
Уоррен П

3
@WarrenP: Концепція "коду, що несе доказ" походить від статично набраних функціональних мов. Ідея полягає в тому, що ви використовуєте систему типів таким чином, щоб функція могла перевірити тип, лише якщо вона правильна, тому той факт, що компілюється код, є доказом правильності. Звичайно, це не повною мірою можливо, зберігаючи цілісність мови та можливість перевірки тексту. Але чим сильніша система типів, тим ближче ви можете наблизитися до цієї мети.
sepp2k

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

3
Найважливіша особливість - це, на мій погляд, узгодження шаблонів. Оптимізувати абстрактне дерево синтаксису зі збігом шаблонів по-дурному просто. Робити це без узгодження зразків часто буває неприємно.
Боб Аман,

38

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

І OCaml, і Haskell мають потужні та стислі можливості узгодження шаблонів.

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


Звучить розумно, але чи це єдине? наприклад, такі речі, як рекурсія хвоста, також зіграють свою роль?
wvd

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

@wvd: Оптимізація рекурсії хвоста - це деталь реалізації, а не функція мови як така, яка робить лінійні рекурсивні функції еквівалентними ітераційному циклу. Рекурсивна функція для проходження зв’язаного списку на мові С виграє від неї так само, як і рекурсивна у списку в схемі.
CA McCann

@wvd gcc C має елімінацію хвоста, як і інші мінливі державні мови
Піт Кіркхем,

3
@camccann: Якщо мовний стандарт гарантує tco (або принаймні гарантує, що рекурсивні функції певної форми ніколи не спричинять переповнення стека або лінійне зростання споживання пам'яті), я вважаю, що ця функція мови. Якщо стандарт цього не гарантує, але компілятор все одно робить це, це функція компілятора.
sepp2k

15

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

В моєму останньому завданні компілятора ми використовували OCaml саме з цієї причини, маніпулюючи кодом C, це був просто найкращий інструмент для виконання цього завдання. Якби люди в INRIA побудували OCaml з різними пріоритетами, це могло б бути не таким вдалим.

Тим не менш, функціональні мови є найкращим інструментом для вирішення будь-якої проблеми, тому логічно випливає, що вони є найкращим інструментом для вирішення цієї конкретної проблеми. QED.

/ me: повертається до моїх завдань Java трохи менш радісно ...


4
-1 для "функціональні мови - найкращий інструмент для вирішення будь-якої проблеми". Якби це було правдою, ми б усі використовували їх скрізь. ;)
Андрій Кротков

15
@Andrei Krotkov: Сьогоднішнє слово дня є факетичним · Вимова: \ fə-ˈsē-shəs \ Функція: прикметник Етимологія: середньофранцузьке facetieux, від facetie jest, від латинського facetia Дата: 1599 1: жартувати чи жартувати часто недоречно : waggish <просто бути нахабним> 2: означати бути жартівливим або смішним: несерйозно <a faceful remark> синоніми бачити дотепним. Крім того, що ви втратили жарт, ваша логіка все ще має недоліки. Ви припускаєте, що всі люди є раціональними дійовими особами, і що, я боюся, це не справедливе припущення.
Ukko

5
Думаю, я пропустив жарт, оскільки знаю людей у ​​реальному житті, які сказали б майже точні речі, за винятком цілком серйозно. Закон По, я здогадуюсь. tvtropes.org/pmwiki/pmwiki.php/Main/PoesLaw
Андрій Кротков

13
@Andrei: Використовуючи ваш аргумент ad populum : "Якщо причина краща за емоційне незнання, ми б усі використовували її скрізь".
Тім Шеффер,

9

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


6

Дивіться також

F # шаблон дизайну

FP групує речі "за операцією", тоді як OO групує речі "за типом" і "за операцією", що є більш природним для компілятора / інтерпретатора.


3
Це стосується того, що в деяких колах теорії мови програмування називається "проблемою виразу". Наприклад, дивіться це запитання , де я демонструю справді жахливий код Хаскелла, який робить речі "розширюваними типами". Навпаки, примушування мови ООП до стилю «розширювані операції», як правило, мотивує шаблон відвідувачів.
CA McCann

6

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


4

Здається, всі пропустили ще одну важливу причину. Написати вбудовану мову домену (EDSL) для парсерів, які в звичайному коді дуже схожі на (E) BNF, досить просто.Комбінатори синтаксичного аналізатора, такі як Parsec, досить легко писати функціональними мовами, використовуючи функції вищого порядку та склад функцій. Не тільки простіше, але і дуже елегантно.

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

Це не єдиний спосіб зробити звичайніші рамки звичайно.

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