高級関数とは
高級関数とは、関数を引数にとって関数を返す関数です。
この記事では、高級関数の説明や、具体的な使い道などについて解説しています。
具体例
ここでは「りあクト!」の第3巻に出てきた以下のコードで解説します。
const skimArgs = <T>(fn: (arg: number | string, ...rest: any[]) => Promise<T>) => (args: Array<number | string>, ...rest: any[]): Promise<T> => fn(args[0], ...rest);
ちなみに、自分はこのコードの意味がわからず、この記事を書くに至りました。
まず、関数skimArgsの引数は以下です。
fn: (arg: number | string, ...rest: any[]) => Promise<T>
「argとrestという引数を受け取ってPromiseを返すfnという関数」が引数になります。
次に、返り値は以下です。
(args: Array<number | string>, ...rest: any[]): Promise<T> => fn(args[0], ...rest);
返り値は「argsとrestを受けとり、fn(args[0], ...rest)を実行してPromiseを返す関数」を意味しています。
具体例として、以下のような関数があるとしましょう。
const originalFunction = async (firstArg: number | string, ...rest: any[]) => {
return `First arg: ${firstArg}, Rest args: ${rest}`;
};
これに対してskimArgs()を適用します。
const newFunction = skimArgs(originalFunction);
このnewFunctionはargsとrestを受け取りoriginalFunction(args[0], ...rest)を実行してPromiseを返す関数です。
そのため
newFunction([1, 2, 3], 'extra', 'arguments').then(result => console.log(result));
のように実行することが可能です。
高級関数の使い道
今回の例で言うと、originalFunctionとnewFunctionの違いは、第1引数の型だけです。
このように、関数の機能を変えず引数だけ変える場合にも有効ですが、他にも色々な使い道があります。
関数の合成
まずは、関数の合成というのがよくある使い道です。
const compose = (f, g) => x => f(g(x)); const add1 = x => x + 1; const double = x => x * 2; const add1ThenDouble = compose(double, add1); // 8が出力される console.log(add1ThenDouble(3));
このcomposeの引数はf, gという2つの関数で、返り値は「xを受け取り、f(g(x))を返す関数」となります。
そのためadd1ThenDoubleは、受け取った数値に1を足して2倍する、という機能の関数になります。
カリー化
他には、カリー化というものがあります。
カリー化とは、関数が複数の引数を取るのではなく、1つの引数を取る関数を連鎖させることで、最終的に複数の引数を処理する手法です。
たとえば、以下のmultiplyは引数がaで、返り値は「bを受け取ってaとの積を返す関数」です。
const multiply = a => b => a * b;
この関数は以下のように使うことができます。
const double = multiply(2); // 6が出力される console.log(double(3));
この例は掛け算をしているだけですが、複雑な処理になるとカリー化を使うメリットが出てきます。
高級関数は一見複雑ですが、慣れると有用なものです。この記事が理解の一助になれば幸いです。