部分適用
関数の引数をあらかじめ埋めます。
「部分適用」はCoddyKit上の無料Lua Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはLua Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Lua Academyコースには全4レッスンが含まれています。
部分適用とは
部分適用とは、関数の引数の一部を先に固定し、残りを後から渡すことです。必要な引数が少なくなった新しい関数が返されます。
これにより、すでに分かっている値を固定して、汎用的な関数を特化した関数に変えられます。
手動で作成する例
add関数があるとします。5を捕捉して、2つ目の数値を待つクロージャを記述すると、addFiveを作成できます。
捕捉された値は返された関数内に保持されるため、呼び出すたびに残りの引数だけを渡せば済みます。
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ヘルパーは関数と固定する最初の引数を受け取り、2つ目の引数を受け取る新しい関数を返します。
クロージャは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 は可変長引数を受け取るため、複数の引数を一度に固定できます。返される関数は、残りの引数だけを受け取ればよくなります。
ここでは3つの引数のうち2つをあらかじめ指定しているため、引数を1つだけ受け取る関数が残ります。
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"))部分適用とカリー化の違い
カリー化では、複数の引数を取る関数を、次の関数を返す単一引数関数の連鎖に変換します。一方、部分適用では一部の引数だけを固定し、残りは通常の呼び出しとして受け取ります。
この2つは関連していますが別のものです。カリー化は1つずつ引数を渡し、部分適用は一部の引数を先に固定します。
local function curryAdd(a)
return function(b)
return function(c)
return a + b + c
end
end
end
print(curryAdd(1)(2)(3))2引数関数のカリー化
小さなヘルパーを使うと、任意の2引数関数を自動的にカリー化できます。最初の引数を受け取って、2番目の引数を受け取る関数を返します。
これにより、パイプライン内で読みやすく使える、再利用可能な単一引数のビルダーを作成できます。
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))使う場面
同じ先頭の引数を何度も指定して関数を呼び出す場合は、部分適用を使って重複を減らせます。
また、1つの値だけを渡すコールバックのように、より少ない引数を想定するインターフェースに関数を適合させる場合にも役立ちます。
設定済みのコールバック
部分適用は map や filter と相性がよい機能です。設定用の引数をあらかじめ指定して、コールバックにはリスト要素だけが渡されるようにできます。
これにより、動作を調整できる柔軟性を保ちながら、パイプラインをすっきりと記述できます。
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, ", "))理解度チェック
関連する2つの考え方の違いを思い出してください。
まとめ
部分適用では一部の引数を固定し、固定値をキャプチャするクロージャによって、残りの引数を受け取る新しい関数を返します。
可変長引数を使う partial ヘルパーはこの仕組みを一般化します。一方、カリー化は単一引数関数を連鎖させます。どちらも重複を減らし、関数をコールバックに適合させるのに役立ちます。
よくある質問
「部分適用」レッスンは無料ですか?
はい。「部分適用」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Lua Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Lua Academyコースには全4レッスンが含まれています。
「部分適用」で何を学びますか?
関数の引数をあらかじめ埋めます。 ブラウザで直接実行するハンズオンコードでLua Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Lua Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのLua Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「部分適用」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このLua Academyレッスンでコードを書いて実行できますか?
はい。すべてのLua Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。