ホームページ > 記事 > ウェブフロントエンド > JSで自動カリー化を実装する方法
JSでの絶妙な自動カリー化方法を詳しく解説し、コード例を通してそのプロセスと原理を分析します。ぜひ参考にして学んでください。
以下のコンテンツでは、コードの説明と例を通してJSでの高度な自動カリー化の実装方法を分析し、カリー化関数の基本的な使い方と知識を学びましょう。
カレーとは何ですか?
コンピューターサイエンスにおいて、カリー化とは、複数のパラメーターを受け入れる関数を、単一のパラメーター (元の関数の最初のパラメーター) を受け入れる関数に変換し、残りのパラメーターを受け入れて結果を返す関数を返すことです。機能技術。この手法は、モーゼス シュンフィンケルとゴットロブ フレーゲによって発明されましたが、論理学者のハスケル カリーにちなんでクリストファー ストラチーによって命名されました。
理論は圧倒的だと思われますか?それは問題ではありません。最初にコードを見てみましょう:
Curriization application
リスト内の各要素に 1 を追加するなど、リスト要素に対して何らかの処理を実行する関数を実装する必要があるとします。 , それから、次のように考えるのは簡単です:
const list = [0, 1, 2, 3]; list.map(elem => elem + 1);
簡単ですよね?さらに 2 つ追加したい場合はどうすればよいでしょうか?
rreeeちょっと非効率な気がしますが、処理関数をカプセル化できますか?
しかし、map のコールバック関数は現在の要素 elem をパラメータとして受け入れるだけです。それをカプセル化する方法はないようです...
次のように思うかもしれません。部分的に設定された関数を取得できればいいのですが、例:
const list = [0, 1, 2, 3]; list.map(elem => elem + 1); list.map(elem => elem + 2);
次のような関数をマップに渡します:
// plus返回部分配置好的函数 const plus1 = plus(1); const plus2 = plus(2); plus1(5); // => 6 plus2(7); // => 9
素晴らしいですね?この方法では、どれだけ追加しても、必要なのは list.map(plus(x)) だけです。これにより、カプセル化が完全に実装され、可読性が大幅に向上します。
しかし、ここで疑問が生じます: このようなプラス関数を実装するにはどうすればよいでしょうか?
ここでカリー化が役に立ちます:
カリー化関数
const list = [0, 1, 2, 3]; list.map(plus1); // => [1, 2, 3, 4] list.map(plus2); // => [2, 3, 4, 5]
ご覧のとおり、カリー化プラス関数は最初にパラメーター a を受け取り、次にクロージャーによりパラメーター b 関数を返します。 function は親関数のパラメーター a にアクセスできるため、たとえば、 const plus2 = plus(2) は function plus2(b) { return 2 + b } と同等になり、部分的な構成が実現されます。
平たく言えば、カリー化は複数パラメーター関数を部分的に構成するプロセスであり、各ステップで単一パラメーターを受け入れる部分的に構成された関数が返されます。極端な場合には、複数の追加など、関数を部分的に何度も設定する必要がある場合があります。
// 原始的加法函数 function origPlus(a, b) { return a + b; } // 柯里化后的plus函数 function plus(a) { return function(b) { return a + b; } } // ES6写法 const plus = a => b => a + b;
この書き方は奇妙に見えますね。しかし、JS での関数型プログラミングの大きな落とし穴に陥ると、これが標準になります。
JS での自動カリー化の絶妙な実装
カリー化は関数型プログラミングの非常に重要な部分です (例: Haskell) は、デフォルトで関数を自動的に変更します。ただし、JS ではこれが行われないため、自動カリー化機能を自分で実装する必要があります。
まずコードを入力してください:
multiPlus(1)(2)(3); // => 6
このようにして自動カリー化が実現します!
何が起こったのか理解できたなら、おめでとうございます!みんながあなたを呼ぶボスはあなたです! 、「いいね!」を残して、職務上のキャリアを開始してください (面白い
何が起こっているのか理解できなくても、心配しないでください。今すぐアイデアを整理するのをお手伝いします。
要件分析
私たちはカレー関数は、カレーされる関数をパラメータとして受け取り、パラメータを受け取る関数を返します。パラメータの数が十分な場合、元の関数が実行され、結果が返されます。
実装方法
簡単に考えると、部分構成関数をカリー化するステップ数は fn のパラメーターの数に等しいことがわかります。これは、2 つのパラメーターを持つ plus 関数を部分的に構成する必要があることを意味します。これは fn.length を通じて取得できます。一般的な考え方は、パラメータが渡されるたびに、パラメータがパラメータ リスト argsList に入れられるということです。 null, argsList) が呼び出されます。これを実現するには、内部判定関数 _c(restNum, argsList) が必要です。1 つは残りのパラメーターの数、もう 1 つはリストです。 ; _c の機能は、渡されていないパラメータがあるかどうかを判断することです。restNum が 0 の場合は、fn.apply(null, argsList) を通じて元の関数を実行し、渡す必要のあるパラメータがまだある場合、つまり、restNum が 0 でない場合は、関数がパラメータを受け取った後、単一パラメータ関数
// ES5 function curry(fn) { function _c(restNum, argsList) { return restNum === 0 ? fn.apply(null, argsList) : function(x) { return _c(restNum - 1, argsList.concat(x)); }; } return _c(fn.length, []); } // ES6 const curry = fn => { const _c = (restNum, argsList) => restNum === 0 ? fn(...argsList) : x => _c(restNum - 1, [...argsList, x]); return _c(fn.length, []); } /***************** 使用 *********************/ var plus = curry(function(a, b) { return a + b; }); // ES6 const plus = curry((a, b) => a + b); plus(2)(4); // => 6
を返す必要があります。パラメータが不足すると、残りのパラメータrestNum が 1 つ減らされ、新しいパラメータ x が再帰呼び出しのために _c に渡されます。その結果、パラメータの数が不十分な場合は、単一パラメータ関数が使用されます。十分なパラメータが返されると、元の関数が呼び出されて返されます。
これで、ES6 の記述方法がより簡単になったように見えます。配列の分割やアロー関数などのシュガー構文を使用していますが、考え方は同じです~function(x) { return _c(restNum - 1, argsList.concat(x)); }他の方法との比較 よく使われる方法:
function curry(fn) { const len = fn.length; return function judge(...args1) { return args1.length >= len ? fn(...args1): function(...args2) { return judge(...[...args1, ...args2]); } } } // 使用箭头函数 const curry = fn => { const len = fn.length; const judge = (...args1) => args1.length >= len ? fn(...args1) : (...args2) => judge(...[...args1, ...args2]); return judge; }
与本篇文章先前提到的方法对比的话,发现这种方法有两个问题:
依赖ES6的解构(函数参数中的 ...args1 与 ...args2);
性能稍差一点。
性能问题
做个测试:
console.time("curry"); const plus = curry((a, b, c, d, e) => a + b + c + d + e); plus(1)(2)(3)(4)(5); console.timeEnd("curry");
在我的电脑(Manjaro Linux,Intel Xeon E5 2665,32GB DDR3 四通道1333Mhz,Node.js 9.2.0)上:
本篇提到的方法耗时约 0.325ms
其他方法的耗时约 0.345ms
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
以上がJSで自動カリー化を実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。