0Pricing
Lua Academy · Урок

Частичное применение

Заранее заполняйте аргументы функций.

«Частичное применение» — бесплатный урок Lua Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Lua Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Lua Academy содержит 4 уроков всего.

Что такое частичное применение

Частичное применение означает, что некоторые аргументы функции фиксируются сейчас, а остальные передаются позже. В результате Вы получаете новую функцию, которой требуется меньше аргументов.

Это позволяет превратить универсальную функцию в специализированную, зафиксировав уже известные Вам значения.

Пример вручную

Предположим, у Вас есть функция add. Вы можете создать addFive, написав замыкание, которое захватывает число 5 и ожидает второе число.

Захваченное значение хранится в возвращённой функции, поэтому при каждом вызове требуется только оставшийся аргумент.

local function add(a, b)
  return a + b
end

local function addFive(b)
  return add(5, b)
end

print(addFive(10))
print(addFive(2))

Фиксация первого аргумента

Можно обобщить этот шаблон. Вспомогательная функция bind1 принимает функцию и фиксированный первый аргумент, а затем возвращает новую функцию, ожидающую второй аргумент.

Замыкание захватывает и f, и зафиксированное значение, а при вызове передаёт все аргументы дальше.

local function bind1(f, a)
  return function(b)
    return f(a, b)
  end
end

local function mul(x, y) return x * y end
local double = bind1(mul, 2)
print(double(7))
print(double(50))

Использование переменного числа аргументов

Чтобы зафиксировать любое количество начальных аргументов, используйте синтаксис переменного числа аргументов Lua .... Сначала захватите фиксированные аргументы, а затем добавьте остальные во время вызова.

Функции table.pack и table.unpack помогают сохранять и раскрывать списки аргументов.

local function partial(f, ...)
  local fixed = table.pack(...)
  return function(...)
    local rest = table.pack(...)
    local args = {}
    for i = 1, fixed.n do args[i] = fixed[i] end
    for i = 1, rest.n do args[fixed.n + i] = rest[i] end
    return f(table.unpack(args, 1, fixed.n + rest.n))
  end
end

local function add3(a, b, c) return a + b + c end
local add10 = partial(add3, 10)
print(add10(2, 3))

Фиксация нескольких аргументов

Поскольку partial принимает переменное число аргументов, можно зафиксировать сразу несколько аргументов. Возвращённой функции тогда нужны только остальные.

Здесь заранее заданы два из трёх аргументов, поэтому получается функция с одним аргументом.

local function partial(f, ...)
  local fixed = table.pack(...)
  return function(...)
    local rest = table.pack(...)
    local args = {}
    for i = 1, fixed.n do args[i] = fixed[i] end
    for i = 1, rest.n do args[fixed.n + i] = rest[i] end
    return f(table.unpack(args, 1, fixed.n + rest.n))
  end
end

local function label(prefix, sep, value) return prefix .. sep .. value end
local tag = partial(label, "id", ":")
print(tag(42))

Практическое применение

Частичное применение особенно полезно для универсальных вспомогательных функций. Один раз задайте конфигурацию, а затем многократно используйте специализированную функцию.

Ниже универсальная функция greet превращается в функцию приветствия на заданном языке, которой нужно только имя.

local function greet(lang, name)
  if lang == "tr" then return "Merhaba, " .. name end
  return "Hello, " .. name
end

local function bind1(f, a) return function(b) return f(a, b) end end
local greetTr = bind1(greet, "tr")
print(greetTr("Ada"))
print(greetTr("Lin"))

Частичное применение и каррирование

Каррирование превращает функцию с несколькими аргументами в цепочку функций с одним аргументом, каждая из которых возвращает следующую. Частичное применение лишь фиксирует часть аргументов, а остальные оставляет для обычного вызова.

Эти подходы связаны, но различаются: при каррировании аргументы обрабатываются по одному, а при частичном применении некоторые аргументы фиксируются сразу.

local function curryAdd(a)
  return function(b)
    return function(c)
      return a + b + c
    end
  end
end

print(curryAdd(1)(2)(3))

Каррирование функции с двумя аргументами

Небольшая вспомогательная функция может автоматически выполнить каррирование любой функции с двумя аргументами. Она возвращает функцию первого аргумента, которая возвращает функцию второго.

Так получаются повторно используемые функции с одним аргументом, которые удобно читаются в конвейерах.

local function curry2(f)
  return function(a)
    return function(b)
      return f(a, b)
    end
  end
end

local function pow(base, exp) return base ^ exp end
local cpow = curry2(pow)
print(cpow(2)(10))

Всё работает благодаря замыканиям

Каждая функция с частичным применением и каждая каррированная функция опирается на замыкания. Зафиксированные аргументы — это захваченные локальные переменные, которые помнит возвращаемая функция.

Поскольку у каждой возвращаемой функции есть собственные захваченные значения, Вы можете безопасно создавать множество специализированных вариантов.

local function bind1(f, a) return function(b) return f(a, b) end end
local function sub(x, y) return x - y end

local from100 = bind1(sub, 100)
local from10 = bind1(sub, 10)
print(from100(40))
print(from10(3))

Когда это применять

Используйте частичное применение, чтобы устранить повторения, если снова и снова вызываете функцию с одними и теми же начальными аргументами.

Оно также помогает адаптировать функцию к интерфейсу, которому нужно меньше аргументов, например к функции обратного вызова, передающей только одно значение.

Настроенные функции обратного вызова

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

Это сохраняет чистоту конвейера и при этом позволяет настраивать поведение.

local function map(t, f) local o={} for i,v in ipairs(t) do o[i]=f(v) end return o end
local function bind1(f, a) return function(b) return f(a, b) end end
local function scale(factor, x) return factor * x end

local r = map({1,2,3,4}, bind1(scale, 10))
print(table.concat(r, ", "))

Быстрая проверка

Вспомните различие между двумя связанными идеями.

Итоги

Частичное применение фиксирует часть аргументов и возвращает новую функцию, ожидающую остальные; это реализуется с помощью замыканий, захватывающих зафиксированные значения.

Вспомогательная функция partial с переменным числом аргументов обобщает этот подход, а каррирование объединяет функции с одним аргументом в цепочку. Оба подхода уменьшают повторения и адаптируют функции к функциям обратного вызова.

Часто задаваемые вопросы

Урок «Частичное применение» бесплатный?

Да — полный текст урока «Частичное применение» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Lua Academy, подпишись на CoddyKit PRO. Курс Lua Academy содержит 4 уроков всего.

Чему я научусь в уроке «Частичное применение»?

Заранее заполняйте аргументы функций. Ты практикуешь Lua Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Lua Academy?

Предыдущий опыт не требуется. Lua Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Частичное применение»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Lua Academy?

Да. Каждый урок Lua Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Функции как значения
  2. map, filter, reduce
  3. Частичное применение
  4. Композиция функций
← Назад к Lua Academy