Ще раз про карування та часткове застосування в PHP

Термінcurryingпоходить від прізвища американського математика Haskell Curry. Друге значення словаcurrying- вироблення дубленої шкіри.
Поняття карірування і часткового застосування походять з функціональних мов програмування, у яких вони знаходять широке застосування. Сучасний PHP виявляє тенденцію до запозичення деяких елементів функціонального програмування (функції як об'єкти першого класу, анонімні функції та замикання), так що концепції, що обговорюються, вже не є для нього зовсім сторонніми.
Емуляція карірування та часткового застосування на PHP — це один з прикладів того, що Макконнелл у «Довершеному коді» (гл. 4.3) називає програмуваннямз використанняммови, а ненамові.
Короткий лікнеп
Каррування та часткове застосування використовуються для побудови фабрик функцій. Ця техніка особливо корисна, якщо треба породити функцію із заданим інтерфейсом для передачі в іншу функцію як аргументу для виконання фільтрації, сортування, перетворення і т. п. Нехай у нас є якась функція з безліччю параметрів і ми хочемо масово будувати функції, що збігаються з даної під час фіксації тих чи інших аргументів.
Наприклад, нехай у нас є «чорна скринька» — функціяsolve(f,x0,ε), яка знаходить рішення рівнянняf(x) = 0 в околиці початкової точкиx0 з точністюε. Тоді за допомогою виклику часткового застосування ми можемо побудувати функцію solve1(x0,ε) ≡ solve(x− tgx,x0,ε). Або навіть функцію solve2(ε), яка вирішувала б якесь фіксоване рівняння в околиці фіксованої початкової точки зі змінною точністю.
Зрозуміло, у кожному окремому випадку ми можемо написати функцію-обгортку типу
проте було зручніше мати універсальний механізм, яким і є часткове застосування.
Каррування - це процедура, що перетворює функцію відnзмінних в ланцюжок зnфункцій однієї змінної, виконуючи послідовну підстановку аргументів. Наприклад, нехай add(a,b) =a+b, a curry_add - результат карірування функції add. Тоді виклик curry_add(a) для кожного a породжуватиме функції одного аргументу, що додають до ньогоa, тобто curry_add(a)(b) = add(a,b). Більше прикладів буде наведено нижче.
Детальніше з каруванням та частковим застосуванням можна ознайомитись у великій статті Є. Кирпічева «Елементи функціональних мов» (розділ 5).
Каруюча функція
Отже, слайди. Все, що нам потрібно, це наступний код, який замінює вихідну функцію її версією.
Класичний приклад
Нехай у нас визначено функцію add.
Ми можемо побудувати її версію.
Перевіримо, що отримана функція поводиться як і, як і вихідна.
Тепер підставимо лише перший аргумент, щоб згенерувати функції інкременту та декременту.
Ще приклади
Ми можемо абсолютно прозоро підставлятидовільна кількість початкових аргументів та отримувати повноцінну функцію, в яку можна знову підставити не всі аргументи. Наприклад,
Результат карування можна без проблем передати як callback-параметр іншої функції. Наприклад, нехай нам треба обчислити маси кубів за щільністю та масивом довжин сторін. Ми можемо зробити це так.
Примітки
- З погляду інтерпретатора PHP результат нашого карірування є функцією, а об'єктом класу Closure, оскільки побудований як анонімне замикання. Проте з погляду синтаксису підміна абсолютно прозора.
- З очевидних причин не можна керувати функціями зі змінним числом аргументів типу printf(). У нашій реалізації всі аргументи функції стають обов'язковими, навіть якщо у вихідній сигнатурі вони були позначені як необов'язкові. Також слід зазначити, що при спробі порахувати кількість аргументів функцій керованої getNumberOfParameters() поверне 0.
- Строго кажучи, функція каррова повинна приймати аргументи по одному, тобто замість $add(2, 5) треба писати $add(2)(5). Однак поточна версія інтерпретатора PHP вважає записи типу func(arg1)(arg2) синтаксичною помилкою, навіть якщо вони семантично вірні. Тому для зручності наша реалізація дозволяє вказувати відразу кілька аргументів через кому, що зближує її з частковим застосуванням.
Хардкорна конфа за С++. Ми запрошуємо лише профі.