背景
TypeScriptを書く際に下記のコードに遭遇し、引数を2つ連続で取ってるのっておかしくね?と思い調べました。調べてみると、関数型プログラミング言語にはカリー化というものがあることを知りました。
export const getBlog = (queries?: MicroCMSQueries) => (contentId: string) =>
apiClient.getListDetail<Blog>({ endpoint: 'blog', contentId, queries })
カリー化とは
カリー化とは、複数の引数をとる関数を、引数が「もとの関数の最初の引数」で戻り値が「もとの関数の残りの引数を取り結果を返す関数」であるような関数にすること(あるいはその関数のこと)である。(Wikipedia)
??
簡単に言うと、
カリー化とは、複数の引数を取る関数を、一度に1つの引数だけを取る一連の関数に変換するテクニックです。これにより、関数の一部の引数を固定して新しい関数を生成することが可能になります。これを部分適用と呼びます。
カリー化・部分適用の具体例
まずは2つの数値を加算するシンプルな関数を作成します。
function add(x: number, y: number): number {
return x + y;
}
この関数は2つの引数を取りますが、カリー化を使用して一度に1つの引数だけを取る関数に変換することができます。
function curriedAdd(x: number) {
return function(y: number) {
return x + y;
}
}
この curriedAdd 関数は、最初の引数 x を取り、その後に新しい関数を返します。この新しい関数は、2番目の引数 y を取り、x と y を加算します。
部分適用を使用すると、一部の引数を固定した新しい関数を生成することができます。例えば、以下のように curriedAdd 関数を部分適用して、5を加算する新しい関数を生成することができます。
const addFive = curriedAdd(5);
console.log(addFive(3)); // 8
console.log(addFive(10)); // 15
この例では、addFive 関数は5を加算する関数です。これは、部分適用を使用して curriedAdd 関数の一部の引数を固定した結果です。
上記を踏まえて再度コード見てみます。
export const getBlog = (queries?: MicroCMSQueries) => (contentId: string) =>
apiClient.getListDetail<Blog>({ endpoint: 'blog', contentId, queries })
これは下記と同じ意味になることが分かります。
export const getBlog = (queries: MicroCMSQueries, contentId: string) =>
apiClient.getListDetail<Blog>({ endpoint: 'blog', contentId, queries });
そして、この関数を使用する場合は以下のようになります:
const queries = {
limit: 10,
offset: 20,
fields: 'title,body'
};
const contentId1 = "contentId1";
const contentId2 = "contentId2";
const contentId3 = "contentId3";
const blog1 = getBlog(queries, contentId1);
const blog2 = getBlog(queries, contentId2);
const blog3 = getBlog(queries, contentId3);
//GET /blog/contentId1?limit=10&offset=20&fields=title,body
//GET /blog/contentId2?limit=10&offset=20&fields=title,body
//GET /blog/contentId3?limit=10&offset=20&fields=title,body
この場合だと、いちいちgetBlog関数の第一引数にqueriesを指定しないといけません。
カリー化と部分適用は、特定の設定で何度も同じ関数を呼び出す必要がある場合などに便利です。また、部分適用された関数を生成することで、コードの可読性も向上します
まとめ
カリー化と部分適用は、関数型プログラミングの重要な要素であり、TypeScriptでも利用することができます。これらを調べるにあたり、第一級関数や高階関数についても調べられたので勉強になりました。
参考