JSで自動カリー化を実装する方法

亚连
リリース: 2018-06-21 13:59:49
オリジナル
1464 人が閲覧しました

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

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

在Vue中有关SPA首屏加载优化(详细教程)

在Angular中有关管道操作符(|)用法

VS Code编辑器中关于修改选中文字或代码颜色操作

以上がJSで自動カリー化を実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
js
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート