В чем разница каррирования и частичного применения в JavaScript
Что проверяют
Различаете ли вы два понятия, которые постоянно смешивают, и понимаете ли, где они встречаются во фронтенд-коде. Следом обычно просят написать универсальную функцию curry или объяснить, чем bind отличается от каррирования.
Как отвечать
Начните с определений через число аргументов:
- каррирование: превращение функции от n аргументов в цепочку функций от одного аргумента.
f(a, b, c)становитсяf(a)(b)(c). Само по себе каррирование ничего не фиксирует, оно меняет только форму вызова; - частичное применение: фиксация части аргументов с получением новой функции от оставшихся. У
add(a, b, c)с зафиксированнымa = 5получается функция(b, c) => ..., которую вызывают один раз; - связь: каррирование делает частичное применение тривиальным, каждый промежуточный вызов и есть частичное применение. Но частично применить можно и некаррированную функцию.
Встроенный способ частичного применения в JavaScript это Function.prototype.bind: add.bind(null, 5) вернёт функцию двух аргументов и попутно зафиксирует this. Встроенного каррирования нет, его пишут сами или берут curry из Lodash или Ramda. Типичная реализация сравнивает число накопленных аргументов с fn.length и либо вызывает исходную функцию, либо возвращает замыкание, которое продолжит сбор. Библиотечные версии разрешают передавать несколько аргументов за раз, строгое каррирование этого не допускает.
Во фронтенде это фабрики обработчиков handleChange(field)(event), мидлвары Redux с сигнатурой store => next => action, настраиваемые валидаторы, композиция через pipe.
Где спотыкаются
Называют каррирование «фиксацией первого аргумента». Это описание частичного применения, каррирование же меняет форму функции и значений не фиксирует.
Пишут curry на основе fn.length и не знают, что параметры со значением по умолчанию и rest-параметры в length не учитываются. У (a, b = 1) => ... длина равна 1, и функция вызовется раньше, чем ожидалось.
Не могут сказать, зачем это в продакшене. Ответ сильнее с одним реальным примером вроде фабрики обработчиков и с оговоркой, что длинные цепочки вызовов ухудшают читаемость и выведение типов в TypeScript.