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


20

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

Мені здається, практичніше було б вивчити Lisp чи Clojure (або Scheme, або Scala тощо), але за тим, що я чув нещодавно, Haskell було б дуже важко перемогти, навчаючи когось принципів функціонального програмування. Я в цьому ще не впевнений, тому запитую вас: яка найчистіша функціональна мова програмування? Замовлення було б чудово, якби кілька змагалися за чудовий заголовок найчистішої функціональної мови програмування.


2
Я вивчив Міранду в університеті, тому я був упередженим, але я запропону Хаскела будь-кому, хто хоче зануритися у функціональну мову, не відволікаючи домішок . * 8 ')
Марк Бут

2
Після того, як ви закінчите навчання функціонального програмування, ви також повинні вивчити статично набране програмування з системою виразного типу. У комбінованій категорії (як функціональної, так і набраної) я пропоную: Coq> Haskell> OCaml> Scala> інші. Є кілька менш популярних альтернатив, які вписуються між Coq і Haskell (наприклад, Epigram і Agda). Haskell не вистачає виразної системи модулів OCaml.
lukstafi

Відповіді:


28

Немає шкали для оцінки ступеня чистоти функціональних мов. Якщо мова дозволяє побічні ефекти, це нечисто, інакше це чисто. За цим визначенням Haskell, Mercury, Clean тощо є чистою функціональною мовою; тоді як Scala, Clojure, F #, OCaml тощо є нечистими.

EDIT: Можливо, я мав би це сформулювати так: "якщо мова не дозволяє побічних ефектів, не повідомляючи про систему типу , вона чиста. Інакше це нечисто."


6
Не зовсім так: Haskell дійсно дозволяє побічні ефекти ( IOмонада). Просто код, що викликає побічні ефекти, чітко позначений як такий. Я не думаю, що взагалі корисно говорити про чисті / нечисті мови (Haskell дозволяє вам програмувати обов'язково! Задихайтесь!), Але все одно може бути корисно говорити про шматки коду (функції, модуля, програми та будь-якого іншого) як чистого / нечистий.
Френк Ширар

8
@Frank: Так, Haskell дозволяє побічні ефекти, але це більше, ніж просто маркування коду, що викликає побічні ефекти. Він також підтримує референтну прозорість навіть при використанні коду, що викликає побічні ефекти, і саме це робить чистою - принаймні, визначенням чистоти багатьох людей. Звичайно, це не відповідає визначенню пропущеного фактора "не допускаються побічні ефекти".
sepp2k

4
@Frank Shearar але корисно говорити в такому способі , тому що IOмонада є чистою. Це бібліотека часу виконання, яка не є вашим кодом, оскільки ваша mainфункція в основному є величезним трансформатором стану. (Щось на кшталт main :: World -> Worldкулісу)
альтернатива

1
Моя мова також має референтну прозорість. Ви просто пишете program = "some C code", і тоді середовище виконання працює з кодом С. :-)
Даніель Лубаров

3
Оскільки друк на екрані є побічним ефектом, справді чисті функціональні програми є досить нудними.

15

Оскільки навчання - ваша мета, а не писати програми як такі, ви не можете отримати чистішого, ніж обчислення Lambda .

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

Вивчення того, як булеві та чисельні видумки і що ifможна винайти з, здавалося б, нічого не додасть більше газу у ваш бак, але це зробить ваш танк набагато більшим.


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

2
Написання доказу - це написання програми, а написання програми - це підтвердження. Коли ви дізнаєтесь про ізоморфізм Кері-Говарда, то зрозумієте, що пройшли цей математичний бар'єр десять тисяч рядків тому.
Macneil

1
Немає простого представлення -1.
Даніель Любаров

2
@ Mason Wheeler: Один тільки λ-обчислення не має цифр або дійсно будь-яких даних, окрім лямбда-абстракцій. Якщо не вказано інше, кожен, хто говорить про числа в λ-обчисленні, мабуть, означає кодування Церкви для натуральних чисел , де число n представлено n-кратним складом функції. Це сказав, я сумніваюсь у тому, що велика боротьба з'ясувати віднімання, коли хтось насправді намагався; Я розробив це самостійно в другій половині дня, даючи лише визначення додавання і знаючи, що віднімання можливо.
CA McCann

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

6

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

Незалежно від того, чи вважаєте ви Haskell чистим чи вважаєте монад IO як домішкою, стиль Haskell є крайньою формою цього стилю і варто цього вивчити.

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

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

Фаза друга - замість генерування текстового вихідного коду ви генеруєте сильно набране дерево абстрактного синтаксису. Ваш обов'язковий компілятор мови поглинається у ваш компілятор "вищого рівня" та приймає AST безпосередньо як вихідний код. Це набагато ближче до того, що робить Haskell.

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

Отже, для фази 3 зробіть обидві однаковими - однакова функція з тим самим синтаксисом може бути частково оцінена під час "генерації коду", або повністю оцінена, або взагалі не оцінена. Крім того, відмовтеся від усіх циклічних конструкцій AST-вузлів на користь рекурсії. Насправді відмовтеся від ідеї вузлів AST як особливого виду даних взагалі - не маєте «буквального значення» вузлів AST, просто маєте значення тощо.

Це в значній мірі те, що робить монада IO - оператор зв'язування - це спосіб складання "дій" для формування програм. Це нічого особливого - лише функція. Багато виразів і функцій можуть бути оцінені під час "генерації коду", але ті, які залежать від побічних ефектів вводу / виводу, повинні мати затримку оцінки до часу виконання - не за яким-небудь спеціальним правилом, а як природний наслідок залежності даних у вирази.

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

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

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

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

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


Дякую! Мені було цікаво, чи могла б узагальнення шаблонів C ++ бути об'єднана у самі функції. Схоже, це робить Haskell, але важлива частина полягає в тому, чи можна це реалізувати компільованою мовою, щоб той самий двигун, що створює загальні функції з шаблонів під час компіляції, також міг оцінювати їх під час виконання ...
Milind R

5

Я особисто класифікую мови на три рівні функціональної чистоти:

  • Чисті функціональні мови - тобто ті, які трактують всю вашу програму як чисту функцію і керуються зміною виключно завдяки взаємодії з режимом виконання - Haskell , мабуть, є канонічним прикладом

  • Нечисті функціональні мови - тобто ті, які підкреслюють функціональний стиль, але дозволяють побічні ефекти. Clojure чітко входить до цієї категорії (вона дозволяє мутації контрольованим чином як частина його STM-рамки), також OCaml або F #

  • Мови мульти-парадигми - це перш за все не функціональні мови, але можуть підтримувати функціональний стиль за допомогою функцій першого класу тощо. Скала - хороший приклад тут, я також ставлю Common Lisp до цієї категорії, і ви навіть можете включити такі мови, як JavaScript .

У вашій ситуації я б запропонував спочатку вивчити Хаскелла, потім Клоджуре. Це я і зробив, і це дуже добре працювало на мене! Haskell прекрасний і вчить вас найчистішим принципам функціонування, Clojure набагато більш прагматичний і допомагає вам багато зробити, в той час як ви ще дуже функціональні.

Я насправді не вважаю третю категорію функціональними мовами (хоча після вивчення Haskell та Clojure я часто виявляю користь функціональних прийомів під час їх використання!)


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

2
@ Дональд стипендіатів: Якщо дурість переходить до нескінченності, кожна мова повного Тьюрінга є функціональною: потрібно просто впровадити інтерпретатор Lisp у мові, а потім використовувати це. :]
CA McCann

Парадигми є безглуздими, якщо прийняти точку зору на те, що все є Тюрінгом завершеним і тому може наслідувати все інше. Коли ви думаєте про парадигми, ви повинні зосередитись на тому, що мова робить ідіоматичним і що це відлякує / заважає. Для моєї точки зору, мутація та побічні ефекти повинні вважатись функціональними (для нечистої ПП) або забороненими (для чистого ПП). Це означає, що C не функціонує. Не існує також мов багатопарадигми, як Scala.
mikera

@mikera: Я вважаю вашу відповідь дуже цікавою: якщо Scala не функціональна, а лише багатопарадигма, як ви оцінюєте функції функціонального програмування в C ++ 11, C # або навіть Java (заплановане введення лямбда)?
Джорджо

@Giorgio: Я думаю, що функціональні функції у всіх мовах, які ви згадуєте, є, мабуть, хорошою ідеєю, вони просто не роблять їх "функціональними мовами". Або дивитись на це з протилежного напрямку, той факт, що ви можете зробити імперативний монадичний IO-стиль, не робить Haskell імперативною мовою :-). Мови мульти-парадигми в основному є результатом, коли ви об'єднуєте функції з безлічі різних парадигм разом і не ставите будь-який конкретний стиль насамперед. IMHO C ++, C # і Java все рухаються до того, щоб бути багатопарадигмою, але ще не зовсім такими, оскільки OOP на основі класу все ще домінує.
mikera

3

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

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

Я зараз скажу: мода програмування дурна і контрпродуктивна. Важливо лише те, що ваша програма коротка, проста в написанні, проста в обслуговуванні і працює правильно. Те, як ви цього досягаєте, не має нічого спільного з динаміками програмування. - Річард Джонс

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


3

Не зовсім серйозна відповідь, але Unlambda повинен бути претендентом. Ви не можете отримати більше "чистого функціоналу", ніж комбінатори SKI.


4
Божевілля! Єресь! Яка чиста мова має абсурди, як комбінатори з побічними ефектами? Ні ні. Те , що ви дійсно хочете тут Лінивий K .
CA McCann

2

Erlang, Haskell, Schema, Scala, Clojure і F #

Це питання, ймовірно , краще ви допомогти вам у вашому пошуку , як добре .


Дякую, справді цікаве запитання. Я почав з PLT-схеми / ракетки, але ще не переглянув SICP ... Реальний світ Haskell виглядає і для мене досить цікаво.
Джоаніс

Схема заохочує функціональний стиль, але він має set!(серед іншого) ...
Даніель Любаров

Я пропоную OCaml, тому що це мій улюблений. І в ньому є модульна система, яку пропускають Haskell і F #.
lukstafi

@lukstafi, можливо, haskell змінився за останні 3 роки (я знаю, що він став божевільним), але в haskell напевно є модулі.
сара

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