Як зазначив Янніс , існує низка факторів, які вплинули на прийняття функцій високого порядку в мовах, які раніше не були. Одним із важливих пунктів, якого він лише злегка торкнувся, є розповсюдження багатоядерних процесорів і, з тим, прагнення до більш паралельної та одночасної обробки.
Мапа / фільтр / скорочення стилю функціонального програмування дуже привітна до паралелізації, що дозволяє програмісту легко використовувати декілька ядер, не записуючи явного коду нарізки.
Як зазначає Джорджіо, функціональне програмування більше, ніж просто функції високого порядку. Функції, плюс карта / фільтр / зменшити схему програмування та незмінність є основою функціонального програмування. Разом ці речі створюють потужні інструменти паралельного та паралельного програмування. На щастя, багато мов вже підтримують певне поняття незмінності, і, навіть якщо вони цього не роблять, програмісти можуть трактувати речі як непорушні, дозволяючи бібліотекам і компілятору створювати та керувати асинхронними або паралельними операціями.
Додавання мови високого порядку до мови є важливим кроком для спрощення одночасного програмування.
Оновлення
Я додам ще кілька докладних прикладів, щоб вирішити проблеми, які зазначив Локі.
Розглянемо наступний код C #, який охоплює колекцію віджетів, створюючи новий список цін віджетів.
List<float> widgetPrices;
float salesTax = RetrieveLocalSalesTax();
foreach( Widget w in widgets ) {
widgetPrices.Add( CalculateWidgetPrice( w, salesTax ) );
}
Для великої колекції віджетів або обчислювально інтенсивного методу CalculateWidgetPrice (Widget) цей цикл не використовує жодних наявних ядер. Щоб зробити розрахунок ціни на різних ядрах, програміст повинен чітко створити та керувати потоками, проходячи навколо роботи та збираючи результати разом.
Розгляньте рішення, як тільки в C # додано функції високого порядку:
var widgetPrices = widgets.Select( w=> CalculateWidgetPrice( w, salesTax ) );
Цикл foreach переміщений у метод Select, приховуючи деталі його реалізації. Все, що залишається програмісту, - це сказати Вибрати, яку функцію застосувати до кожного елемента. Це дозволить реалізації програми Select запустити обчислення паралельно, обробляючи всі проблеми синхронізації та управління потоками без участі програміста.
Але, звичайно, Select не робить це паралельно. Ось де відбувається незмінність. Реалізація Select не знає, що надана функція (CalculateWidgets вище) не має побічних ефектів. Функція могла змінити стан програми поза зоною вибору та її синхронізацією, порушивши все. Наприклад, у цьому випадку значення SalesTax можна змінити помилково. Чисті функціональні мови забезпечують незмінність, тому функція Select (map) може точно знати, що жоден стан не змінюється.
C # вирішує це, надаючи PLINQ як альтернативу Linq. Це виглядатиме так:
var widgetPrices = widgets.AsParallel().Select(w => CalculateWidgetPrice( w, salesTax) );
Що дозволяє повною мірою використовувати всі ядра вашої системи без явного управління цими ядрами.