У чому полягає значення функціонального програмування?
Функціональне програмування за принципом декларативне . Ви кажете, що ваш результат, а не як його обчислити.
Давайте розглянемо дійсно функціональну реалізацію вашого фрагмента. У Haskell це було б:
predsum pred numbers = sum (filter pred numbers)
Чи зрозуміло, який результат? Зовсім так, це сума чисел, що відповідають присудку. Як це обчислюється? Мені все одно, запитайте у компілятора.
Ви, можливо, можете сказати, що використовувати sum
і filter
хитрість, і це не враховується. Нехай тоді реалізують це без цих помічників (хоча найкращим способом було б спочатку їх реалізувати).
Рішення "Функціональне програмування 101", яке не використовується, sum
є з рекурсією:
sum pred list =
case list of
[] -> 0
h:t -> if pred h then h + sum pred t
else sum pred t
Досі зрозуміло, що є результатом в частині виклику однієї функції. Він є або 0
, або recursive call + h or 0
залежно від цього pred h
. І все-таки досить прямо, навіть якщо кінцевий результат не відразу очевидний (хоча, маючи трохи практики, це дійсно читається так само, як for
цикл).
Порівняйте це з вашою версією:
public int Sum(Func<int,bool> predicate, IEnumerable<int> numbers){
int result = 0;
foreach(var item in numbers)
if (predicate(item)) result += item;
return result;
}
Який результат? О, я не бачу: одне return
заяву, не дивує тут: return result
.
Але що таке result
? int result = 0
? Не здається правильним. Ви робите щось пізніше з цим 0
. Гаразд, ви додасте item
до нього s. І так далі.
Звичайно, для більшості програмістів це досить очевидно, що трапляється в такому простому функціонері, але додайте додаткову return
заяву або так, і це раптом стає важче відстежити. Весь код про те , як і що залишається читачеві розібратися - це, очевидно, дуже імперативний стиль .
Отже, чи не змінні змінні та петлі?
Ні.
Є багато речей, які набагато простіше пояснити їм, і багато алгоритмів, які потребують швидкого зміни стану. Але змінні по суті є імперативними, пояснюючи, як замість чого , і не даючи передбачень того, яке їх значення може бути через кілька рядків пізніше або після декількох ітерацій циклу. Петлі, як правило, потребують стану, щоб мати сенс, і тому вони також є суттєво необхідними.
Змінні та петлі - це просто не функціональне програмування.
Підсумок
Сучасне функціональне програмування - це трохи більше стилю та корисного способу мислення, ніж парадигма. Сильна перевага для чистих функцій є в цьому режимі мислення, але насправді це лише невелика частина.
Найбільш поширені мови дозволяють використовувати деякі функціональні конструкції. Наприклад, у Python ви можете вибрати:
result = 0
for num in numbers:
if pred(result):
result += num
return result
або
return sum(filter(pred, numbers))
або
return sum(n for n in numbers if pred(n))
Ці функціональні вирази чудово підходять для таких проблем і просто роблять код коротшим (а коротше - добре ). Не варто бездумно замінювати імперативний код на них, але коли вони підходять, вони майже завжди є кращим вибором.
item
змінна мутується в циклі.