JavaScriptにおけるカリー化解説
JavaScriptにおける「Currying」の解説
Curryingとは、多引数関数(複数の引数を取る関数)を、単引数関数(1つの引数を取る関数)のネストされた適用として表現する手法です。つまり、多引数関数を、引数を1つずつ受け取って新たな関数を返す関数の連鎖として表すことができます。
JavaScriptにおけるCurryingの例を見てみましょう。
function add(x, y) {
return x + y;
}
// Curried version of add
function curriedAdd(x) {
return function(y) {
return x + y;
};
}
ここで、curriedAdd
は、最初の引数x
を受け取って、y
を受け取る関数を返す関数です。この内側の関数は、x
を固定した状態で、y
を受け取ってx + y
を返します。
Curryingの利点
- 関数合成
Curryingと関数合成を組み合わせて、複雑な関数をシンプルな関数の組み合わせから構築することができます。 - 再利用性
部分的に適用された関数を他の関数に渡すことで、再利用が可能になります。 - コードの簡潔性
多引数関数をより小さな単引数関数に分解することで、コードが読みやすくなります。
JavaScriptにおけるカリー化のコード例解説
コード例1:基本的なカリー化
function add(x, y) {
return x + y;
}
// カリー化されたadd関数
function curriedAdd(x) {
return function(y) {
return x + y;
};
}
解説
- curriedAdd関数
- 外側の関数
x
を1つ受け取ります。 - 内側の関数
y
を受け取り、x
とy
を足し合わせた結果を返します。 - カリー化の仕組み
curriedAdd
は、x
の値を固定した状態で、y
を受け取る新たな関数を返します。
- 外側の関数
- add関数
これは通常の、x
とy
の2つの引数を受け取って足し算を行う関数です。
使い方の例
// add関数の使い方
console.log(add(2, 3)); // 出力: 5
// curriedAdd関数の使い方
const add5 = curriedAdd(5); // x = 5に固定した関数を作成
console.log(add5(3)); // 出力: 8
コード例2:複数の引数を持つ関数のカリー化
function multiply(x, y, z) {
return x * y * z;
}
// カリー化されたmultiply関数
function curriedMultiply(x) {
return function(y) {
return function(z) {
return x * y * z;
};
};
}
curriedMultiply
は、引数を1つずつ受け取って、新たな関数を返す関数をネストすることで、3つの引数を持つ関数をカリー化しています。multiply
関数は3つの引数を受け取ります。
const multiplyBy2 = curriedMultiply(2);
const multiplyBy2And3 = multiplyBy2(3);
console.log(multiplyBy2And3(4)); // 出力: 24
カリー化の利点
- 高階関数
関数を引数として受け取ったり、関数を返したりする高階関数との親和性が高いです。 - 関数合成
カリー化された関数を組み合わせることで、より複雑な関数を構築できます。 - 部分適用
関数の引数を一部固定して、新たな関数を作成することができます。
カリー化は、多引数関数をより柔軟に扱うための手法です。JavaScriptの関数型プログラミングにおいて、コードの可読性や再利用性を高めるために活用されます。
ポイント
- 関数合成によって、複雑な処理を複数のシンプルな関数に分割することができます。
- 部分適用によって、特定の値で固定された関数を生成できます。
- カリー化は、関数をネストして、引数を1つずつ受け取るようにすることで実現されます。
- カリー化は、関数型プログラミングの概念ですが、手続き型プログラミングでも利用できます。
- JavaScriptでは、
_.curry
のようなライブラリ関数を使用して、より簡単にカリー化を行うことができます。
カリー化の代替手法とJavaScriptにおける解説
カリー化の代替手法
カリー化は、多引数関数を単引数関数に分解することで、関数型プログラミングにおいて柔軟な処理を実現する手法です。しかし、必ずしもカリー化を用いなくても、同様の目的を達成できることがあります。
可変長引数
- デメリット
- 引数の型が異なる場合の扱いが複雑になることがある。
- 関数の内部で引数を処理するロジックが複雑になる可能性がある。
- メリット
- 引数の数が事前に決まっていない場合に柔軟に対応できる。
- 書き方がシンプルになる場合がある。
function sum(...args) {
return args.reduce((acc, cur) => acc + cur, 0);
}
オブジェクト
- デメリット
- オブジェクトの作成オーバーヘッドが生じる。
- オブジェクトのキー名や値の型を管理する必要がある。
function add({ x, y }) {
return x + y;
}
配列
- デメリット
- 引数の順番を意識する必要がある。
function multiply(numbers) {
return numbers.reduce((acc, cur) => acc * cur, 1);
}
Partial Application(部分適用)
- デメリット
- カリー化よりも複雑な場合がある。
- メリット
- カリー化と似ているが、より柔軟な部分適用が可能。
- ライブラリによっては、部分適用を簡単に実行できる関数を提供している。
// Lodashの例
const _ = require('lodash');
const multiplyBy2 = _.partial(multiply, 2);
JavaScriptにおけるカリー化と代替手法の比較
javascript functional-programming terminology