Якщо ми можемо робити функціональне програмування за допомогою Python, чи потрібна нам конкретна функціональна мова програмування? [зачинено]


22

Використовуючи генератори та лямбда, ми можемо робити функціональне програмування з Python. Те ж саме можна досягти і з Рубі.

Отже, питання: навіщо нам потрібні конкретні функціональні мови програмування, такі як Erlang, Haskell та Scheme? Чи є щось інше, що забезпечують ці конкретні функціональні мови програмування? Чому ми не можемо просто використовувати Python для функціонального програмування?


30
все це було ще до того, як був створений пітон
Махмуд Хоссам

51
Форд Пінто - автомобіль. Навіщо нам потрібні такі швидкі машини, як Ferraris?
Мартін Йорк

11
Використовуючи класи та шаблони, ми можемо робити що завгодно OO в C ++. Чому Java та Python були коли-небудь створені? Що вони додають?
9000

19
Усі мови програмування (без деяких суто академічних мов дослідження) є еквівалентними Тьюрінга, тому те, що можна зробити мовою A, можна зробити будь-якою іншою мовою. Отже, слідуючи за цією думкою думок, нам потрібна лише одна повна мова Тюрінга - скажімо, як sendmail.cf;) okmij.org/ftp/Computation/#sendmail-Turing
Maglob

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

Відповіді:


20

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

Чистота

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

Продуктивність

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

Оптимізація хвостових викликів

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

Синтаксис

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

  • Синтаксис лямбда-функцій досить багатослівний і обмежений тим, що вони можуть містити
  • Немає синтаксичного цукру за складом функції, тобто f = g . hvs.f = lambda *arg: g(h(*arg))
  • Немає синтаксичний цукор для часткового застосування тобто f = map gпротиf = functools.partial(map, g)
  • Немає синтаксичного цукру для використання операторів інфікування у функціях вищого порядку, тобто sum = reduce (+) lstvs.sum = reduce(operator.add, lst)
  • Немає відповідності шаблонів або захистів для аргументів функції, які полегшують вираження умов кінця рекурсії та деяких випадкових меж з дуже читабельним синтаксисом.
  • Дужки ніколи не є додатковими для викликів функцій, і для вкладених дзвінків немає синтаксичного цукру. Я думаю, це питання смаку, але особливо у функціональному коді, я вважаю, що це звичайно для ланцюжкових викликів функцій, і мені стає y = func1 $ func2 $ func3 xлегше читати, ніж y = func1(func2(func3(x)))колись ти знайомий з цим позначенням.

28

Це найважливіші відмінності:

Хаскелл

  • Ледача оцінка
  • Компілює машинний код
  • Статичне введення гарантує, що функції чисті
  • Введіть умовивід

Хаскелл і Ерланг

  • Узгодження шаблону

Ерланг

  • Акторська модель паралельності, легких процесів

Схема

  • Макроси

Усі мови

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

Крім того, ви повинні ознайомитись з такими мовами, як сімейство ML, як SML, Ocaml, F # і Scala, яка по-новому з’єднує OO та функціональне програмування. Всі ці мови мають унікальні цікаві особливості.


3
+1 хороший пост. Ви можете додати висновок про тип у процесах Haskell та Light-weight на Erlang.
Йонас

1
У Python є карта, фільтрування та складання (зменшення). Щодо "реальних закриттів": Якщо ви визначаєте справжнє закриття як закриття, яке може містити щось інше, ніж один вираз, у Haskell немає і справжніх закриттів (але, звичайно, у Haskell є мало речей, які не є виразами ...) . Однак питання про незмінні структури даних є хорошим, тому +1 для цього. Також: хвостова рекурсія (і взагалі менш дорога рекурсія).
sepp2k

2
+1 для "статичного набору тексту забезпечує функції чистими". Дуже круто мати систему типу, яка розмежовує чисті та нечисті функції. (C ++ 's const doe snot count. :)
Макке

1
@btilly: Я б не вважав це закриттям, якщо ви не можете призначити змінну, яка знаходиться в області застосування. В іншому випадку ми повинні сказати, що у Java є і закриття, оскільки ви можете використовувати ту саму хитрість там.
Кім

3
Під час закриття я можу отримати доступ до змінної тими ж способами, що і зазвичай. Це стосується закриттів Хаскелла та Рубі, але не про поганих замінників Python або Java. Можливо, хтось ще може нас потішити про Ерланг, я цього не знаю.
Кім

19

Важко точно визначити, що таке "функціональна мова" - з перерахованих мов, лише Haskell є чисто функціональним (усі інші застосовують якийсь гібридний підхід). Існують певні мовні функції, які дуже корисні для функціонального програмування, однак у Ruby та Python їх недостатньо, щоб вони були дуже хорошими середовищами для FP. Ось мій особистий контрольний список за важливістю:

  1. Першокласні функції та закриття (Ruby, Python та всі інші, які ви перераховували, мають це).
  2. Гарантована оптимізація виклику (Erlang, Haskell, Scala та Scheme) мають це, але не Python, Ruby або Clojure (поки що).
  3. Підтримка непорушності в мовних та стандартних бібліотеках (це велике значення у всіх перерахованих вами "функціональних мов" (крім схеми), але у Ruby та Python немає).
  4. Підтримка мовного рівня для референтно прозорих (чистих) функцій (наскільки я знаю, наразі це має лише Haskell).

Потреба в (1) повинна бути очевидною - функції вищого порядку надзвичайно важкі без функцій першого класу. Коли люди говорять про те, що Ruby та Python є хорошими мовами для FP, вони зазвичай говорять про це. Однак ця особливість необхідна, але недостатня, щоб зробити мову корисною для FP.

(2) є традиційною необхідністю для ПП ще з часу створення схеми. Без TCO неможливо програмувати з глибокою рекурсією, яка є одним з наріжних каменів FP, оскільки ви отримуєте переповнення стека. Єдиною "функціональною" (за популярним визначенням) мовою, якої немає, є Clojure (через обмеження JVM), але Clojure має різноманітні хаки для імітації TCO. (FYI, Ruby TCO є специфічним для впровадження , але Python спеціально не підтримує його .) Причина TCO повинна бути гарантована в тому, що якщо це специфічна для впровадження, глибока рекурсивна функція порушиться з деякими реалізаціями, тому ви не можете реально використовувати їх взагалі.

(3) - ще одна важлива річ, яку мають сучасні функціональні мови (особливо Haskell, Erlang, Clojure та Scala), яких не мають Ruby та Python. Не вдаючись до занадто багато деталей, гарантована незмінність усуває цілі класи помилок, особливо в паралельних ситуаціях, і дозволяє створити акуратні речі, такі як стійкі структури даних . Дуже важко скористатися цими перевагами без підтримки мовного рівня.

(4) - для мене найцікавіше щодо суто функціональних мов (на відміну від гібридних мов). Розглянемо наступну надзвичайно просту функцію Ruby:

def add(a, b)
  a + b
end

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

З чисто функціональної мови, з іншого боку, існують гарантії на рівні мови, що функції є прозоро прозорими. Це має численні переваги: ​​чисті функції легко запам'ятовуються; їх можна легко перевірити, не покладаючись на якийсь глобальний стан; а значення в межах функції можна оцінити ліниво або паралельно, не турбуючись про проблеми одночасності. Haskell повністю використовує це, але я не знаю достатньо інших функціональних мов, щоб знати, чи є вони.

Враховуючи це, можна використовувати методи FP майже на будь-якій мові (навіть на Java). Наприклад, MapReduce від Google натхненний функціональними ідеями, але, наскільки я знаю, вони не використовують жодних "функціональних" мов для своїх великих проектів (я думаю, що вони в основному використовують C ++, Java та Python).


2
+1 для ґрунтовного пояснення - навіть я як аутсайдер FP це зрозумів. Спасибі! :-)
Петер Тьорьк

найцінніша відповідь на це питання досі. Заснований на фактах та великій кількості інформації. Чудова робота.
wirrbel

У Scala є хвоста-рекурсія, і, як і у Scheme, вона виконується автоматично, якщо рекурсивний виклик знаходиться в положенні хвоста (на відміну від Clojure, де його потрібно чітко запитувати). Там навіть анотація , так що ви можете перевірити , що компілятор буде генерувати хвіст рекурсивного коду. Що у неї немає, це більш узагальнений ТСО схеми. Я припускаю, що ви це знаєте, але оскільки ви детально описували більшість інших речей, це здавалося дивним звільненням / упущенням.
йогобрюс

@itsbruce Цей пост досить старий, у IIRC Scala його тоді не було (або я просто помилявся;). Оновлено.
shosti

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

11

Мови, які ви згадуєте, дуже різні.

У той час як Python and Ruby є динамічно набраними мовами, Haskell вводиться статично. Ерланг є одночасною мовою і використовує модель Актора і сильно відрізняється від усіх інших мов, які ви згадуєте.

У Python and Ruby є багато імперативних конструкцій, тоді як у більш чистій функціональній мові, як Haskell, все повертає щось або іншими словами все є функцією.


@kRON: Добре, що система типу є важливою властивістю мови, і він запитав "Чи є щось інше, що надають ці конкретні функціональні мови програмування?". Звичайно, ви можете використовувати модель Actor з іншими мовами, але Ерланг має вбудовану мову. Ерланг використовує легкі процеси та має вбудовані мовні конструкції для розподіленого програмування - звідси "паралельна" мова.
Йонас

8

Пізно на вечірку, як завжди, але все одно буду говорити.

Функціональна мова програмування не є мовою, яка дозволяє функціональне програмування. Якби ми йшли за цим визначенням, то практично будь-яка мова будь-де є функціональною мовою програмування. (Це ж стосується, до речі, OOP. Ви можете писати в стилі OOP на C, якщо вам подобається. Таким чином, за вашою логікою, C є мовою OOP.)

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

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

То чому ми маємо функціональні мови програмування, коли Python (або Ruby (або вставити мову на ваш вибір)) може "робити функціональне програмування"? Тому що Python та ін не можуть виконувати належне функціональне програмування. Ось чому.


6

Ви можете виконувати функціональне програмування на Java (див., Наприклад, http://functionaljava.org/ ). Ви можете також зробити об'єктно - орієнтоване програмування на C . Це просто не так ідіоматично.

Так що на насправді ми не зовсім потрібні Erlang, Haskell, Scheme, або будь-яку мову програмування конкретного, але всі вони представляють собою різні підходи і різні компроміси, роблячи деякі завдання простіше і деякі складніше. Що ви повинні використовувати, залежить від того, що ви хочете досягти.


4

Це питання можна застосувати до нескінченної кількості мов та парадигм.

  • Оскільки всі використовують C ++, навіщо нам потрібні інші мови загального призначення?
  • Оскільки java - це така чудова мова OO, чому існують інші мови OO?
  • Оскільки perl - це дивовижна сценарна мова, навіщо нам потрібен python?
  • Ятта, ятта, ятта

Більшість, якщо не всі мови існують з певної причини. Вони існують тому, що у когось була потреба, яку не заповнювала нинішня мова, або заповнена погано. (Це, звичайно, не стосується кожної мови, але я вважаю, що це стосується більшості відомих мов.) Наприклад, python був спочатку розроблений для взаємодії з ОС Amoeba [ 1 , 2 ], і Erlang був створений, щоб допомогти у розробці додатків для телефонії [ 3 ]. Отож одна відповідь на запитання "Навіщо нам потрібна інша функціональна мова?" може бути просто тому, що [встав-ім’я когось-хто-хто-вміє-як розробляти мови] не сподобалось, як це робив python.

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


2

Функціональне програмування - це стільки як парадигма дизайну, скільки і конкретні мовні особливості. Або, кажучи іншим способом, лямбда і функція карти не є функціональною мовою програмування. У Python та Ruby є деякі функції, натхненні функціональними мовами програмування, але ви все ще в основному пишете код вкрай необхідним чином. (Це схоже на C: ви можете написати OO-подібний код на C, але ніхто серйозно не вважає C мовою OO.)

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


0

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


0

Кожна концепція, наявна в лямбда-обчисленні, LISP та Scheme, доступна в Python, так що так, ви можете робити в ній функціональне програмування. Якщо це зручно чи ні - це питання контексту та смаку.

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

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


@Arkaaito Але ви згодні з тим, що кожна концепція, наявна в обчисленні лямбда, LISP та Schema , доступна в Python?
Марк C

Ви впевнені, що кожна концепція lisp доступна в Python? Макроси, код-це-дані?
SK-логіка

@ SK-логіка Макроси не містять лямбда-числення, але так, вони доступні в Python, хоча не під цим ім'ям. Python надає eval()функцію, яка потрібна для коду - це дані , але вона йде далі: вона дозволяє змінювати більшу частину середовища виконання, як у LISP.
Апалала

@Apalala, динамічні мови eval()- це метапрограмування часу виконання. Іноді це корисно, але це надзвичайно дорого. Макроси Lisp різні, це метапрограмування часу компіляції. Він не доступний в Python в будь-якій формі, що використовується.
SK-логіка

@ SK-логіка. Такі макроси порушують приміщення коду - це дані , оскільки програми не можуть змінювати макроси (або навіть знати про їх існування). У програмі Python програми мають доступ до власних дерев розбору під час виконання, якщо вони потребують. Макроси (статична попередня обробка) взагалі не функціональні.
Апалала

-5

Тому що Python також може програмувати у нефункціональному стилі, а це недостатньо добре для пуриста FP. Однак більш прагматичні кодери можуть користуватися перевагами функціонального стилю, не будучи догматичними щодо цього:

«Функціональний програміст звучить скоріше як середньовічний монах, відмовляючи собі в задоволеннях життя в надії, що це зробить його доброчесним. Для тих, хто більше цікавиться матеріальними благами, ці «переваги» не дуже переконливі. Функціональні програмісти стверджують, що є великі матеріальні вигоди ... [але] це очевидно смішно. Якби пропущення заяв про призначення принесло такі величезні переваги, тоді програмісти FORTRAN робили б це протягом двадцяти років. Логічна неможливість зробити мову більш сильною, опускаючи функції, незалежно від того, наскільки вони погані. "

- Джон Х'юз, чому функціональне програмування має значення


6
Я згоден. Будь-яка мова без gotoцього страшна.
Анон.

2
@Anon: Або його великий побратим call-with-current-continuation.
Кріс Єстер-Янг

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

2
@ Мейсон: так, автор стверджує, що модуляризація та ледача оцінка є справжніми перевагами. Але зауважте, як ваша оригінальна цитата виходила з контексту - ви, здається, припускаєте, що автор вимагає чогось проти ФП, коли насправді ви цитували абзац з паперу з висновком, що FP - це чудово, тільки не з оманливої ​​причини " менше значить більше". Заголовок статті досить чітко показує наміри автора: "чому функціональне програмування має значення" ;-) Це, безумовно, не підтверджує ваше твердження про те, що чистіші моменти FP "неприємність".
Андрес Ф.

6
@ Мейсон Уілер: Гібридні мови передують Python в розрізі loooooong. Наприклад, Лісп датується 1959 роком і, власне, є багатопарадигмічною мовою. Він повністю підтримує функціональні підходи, процедурні підходи та об'єктно-орієнтовані підходи до програмування. З правильними макро-пакетами зверху ви також можете легко програмувати логіку. Схема теж передує Python (і цей документ). Це сягає 1975 року. Можливо, вам варто колись поглянути на цю шкалу мов програмування .
ДАЙТЕ МОЕ правильне ДУМКА
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.