Важко точно визначити, що таке "функціональна мова" - з перерахованих мов, лише Haskell є чисто функціональним (усі інші застосовують якийсь гібридний підхід). Існують певні мовні функції, які дуже корисні для функціонального програмування, однак у Ruby та Python їх недостатньо, щоб вони були дуже хорошими середовищами для FP. Ось мій особистий контрольний список за важливістю:
- Першокласні функції та закриття (Ruby, Python та всі інші, які ви перераховували, мають це).
- Гарантована оптимізація виклику (Erlang, Haskell, Scala та Scheme) мають це, але не Python, Ruby або Clojure (поки що).
- Підтримка непорушності в мовних та стандартних бібліотеках (це велике значення у всіх перерахованих вами "функціональних мов" (крім схеми), але у Ruby та Python немає).
- Підтримка мовного рівня для референтно прозорих (чистих) функцій (наскільки я знаю, наразі це має лише 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).