Partial Application

Частичное применение — закрепление части аргументов функции с получением новой функции от оставшихся. В отличие от каррирования, partial — это один шаг, не цепочка.

Что это / Зачем

  • Дана f(a, b, c), фиксируем a = 1 → получаем g(b, c) = f(1, b, c)
  • Способ из конкретной функции породить более конкретную
  • Базовый кирпич для каррирования и декораторов
  • В стандарте есть Function.prototype.bind — это и есть partial

Примеры

Через bind

const log = (n, base) => Math.log(n) / Math.log(base);

const lg = log.bind(null, 10);     // log по основанию 10
const ln = log.bind(null, Math.E); // натуральный
lg(100); // 2

Своя реализация

const partial = (fn, ...preset) =>
  (...later) => fn(...preset, ...later);

const sum4 = (a, b, c, d) => a + b + c + d;
const f1 = partial(sum4, 1);      // a = 1
const f12 = partial(f1, 2);        // a = 1, b = 2
f12(3, 4); // 10

Partial vs Currying

Partial Currying
Один шаг закрепления Цепочка из n функций
Возвращает функцию любой арности Каждая возвращает функцию от 1 (или больше)
bind — встроенная реализация Нужна своя реализация
Удобен ситуативно Удобен системно
// partial: один шаг, остаток сразу
const add5 = partial(add, 5);
add5(3, 7);        // a=5, b=3, c=7

// curry: цепочка шагов
const cAdd = curry(add);
cAdd(5)(3)(7);     // три отдельных вызова

Ключевые правила

  • bind закрепляет аргументы слева направо
  • Первый аргумент bindthis, дальше — аргументы
  • Лямбды (arrow functions) не привязывают this через bind, но аргументы закрепляются
  • Можно делать последовательно: partial(partial(f, 1), 2)

Подводные камни

  • bind(null, ...) оставляет this = null — может ломать методы
  • Стрелочная функция не знает про this из bind
  • В цепочке partial каждый вызов создаёт новую функцию (память)

🎓 Источник: Частичное применение и каррирование в JavaScript

  • 📅 2018-10-08 · YouTube · ID: ND8KQ5xjk7o
  • Тезисы:
    • Из конкретной функции (Math.log) делаем абстрактную (log с основанием), потом снова конкретную (lg, ln) — это функциональное наследование
    • bind — встроенный partial, закрепляет слева, первый аргумент — this (null если не нужен)
    • Лямбды не работают с bind для this, но для аргументов работают
    • Своя реализация через rest + spread проще и не требует null
  • Цитата: «Это получилось некоторого рода наследование, функциональное наследование. То есть мы сначала от более конкретной функции перешли на более абстрактную, потом унаследовали от нее две других и вычислили.»

См. также