🤖

【関数】引数の要件に合わないときの解決法:アダプター関数

に公開

目的

関数が引数として関数を使用する際に、呼び出し元と呼び出し先で期待する引数の個数が異なる場合の対応方法として、アダプター関数があることを理解すること

例: 関数をラップするデコレータ関数を実装するとき

元のフィボナッチ数列を求める関数に文字列を追加する関数を定義します。

function addStringDecorator(f){
    return function(arg){
        console.log("start fibonacci!");
        // 元の関数を実行
        const result = f(arg);
        return result;
    }
}

この addStringDecorator に引数として 引数が3つ必要なフィボナッチ関数を追加することを考えます。

function fibonacci(fib1, fib2, n) {
    if(n <= 0) return fib1;
    return fibonacci(fib2, fib1 + fib2, n-1);
}

課題

デコレータ addStringDecorator 関数は1つの引数を期待しています。
ここに、addStringDecorator(fibonacci) のように、fibonacci 関数を引数として指定すると、addStringDecorator 関数は1つの引数を期待しているのに、fibonacci 関数は3つの引数を期待しているという、引数の不一致という問題が発生します。

解決策

アダプター関数を使用し、引数の不一致を解消する

現状のズレは、addStringDecorator 関数と fibonacci 関数の引数の個数の違いによって起きています。

したがって、addStringDecorator 関数に渡す引数を1つにする必要があります。

そこで、アダプター関数を使用して、両者のズレを矯正していきます。

アダプター関数の役割

1. デコレーターの仕様

addStringDecorator は、ラップする関数がただ一つの引数を取ることを期待しています。

function addStringDecorator(f){ // 引数は1つ必要
    return function(arg){
        console.log("start fibonacci!");
        const result = f(arg);
        return result;
    }
}

2. 元の関数の仕様

fibonacci は、フィボナッチの計算に必要な3つの引数を必要とします。

function fibonacciFast(fib1, fib2, n) { // 引数は3つ必要
    if(n <= 0) return fib1;
    return fibonacciFast(fib2, fib1 + fib2, n-1);
}

3. ラムダ式による解決

この仕様の不一致を解消するために、ラムダ式(n => fibonacci(0, 1, n))がアダプターとして機能します。

単一引数の受け入れ

ラムダ式は、デコレーターの仕様を満たすため、外側から単一の引数 n のみを受け取ります。

引数の固定と変換

ラムダ式の内部で、フィボナッチ計算に必要な初期値 (0 と 1) を固定し、受け取った n と合わせて3つの引数に変換し、fibonacci を呼び出します。

const strAddedFibonacci = addStringDecorator(n => fibonacci(0,1,n));
console.log(strAddedFibonacci(10));

// 出力結果
start fibonacci!
55

これにより、「一つの引数しか取れない」というデコレーターの制約を守りつつ、「複数の引数が必要な」元の関数を実行することが可能になっています。

まとめ

  • 関数の引数に関数を渡す高階関数において、高階関数における引数の数と引数として使用する関数に必要な引数の数が一致しないときは、ラムダ式(アロー関数)の使用を検討すること

最後までお読みいただき、ありがとうございました。

参考URL

https://recursionist.io/dashboard/course/3/lesson/535

https://learn.microsoft.com/ja-jp/cpp/standard-library/functional?view=msvc-170

Discussion