181

私はまだカレーに慣れていないと思います。私はそれが何をするのか、そしてそれを行う方法を理解しています。使うシチュエーションが思い浮かびません。

JavaScript のどこでカリー化を使用していますか (またはそれを使用している主要なライブラリはどこですか)? DOM 操作または一般的なアプリケーション開発の例を歓迎します。

答えの1つはアニメーションに言及しています。のような関数は引数として要素slideUpfadeIn取り、通常はデフォルトの「アニメーション関数」が組み込まれた高次関数を返すカリー化された関数です。いくつかのデフォルトで上位関数を適用するよりも優れているのはなぜですか?

それを使用することの欠点はありますか?

JavaScript のカリー化に関する優れたリソースを以下に示します。

コメントが増えたら追加します。


したがって、答えによると、カリー化と部分適用は一般的に便利な手法です。

高レベル関数を同じ構成で呼び出して頻繁に「改良」する場合は、高レベル関数をカリー化 (または Resig のパーシャルを使用) して、シンプルで簡潔なヘルパー メソッドを作成できます。

4

17 に答える 17

115

これは、クロージャーを使用する JavaScript でのカリー化の興味深い実用的な使用法です

function converter(toUnit, factor, offset, input) {
    offset = offset || 0;
    return [((offset + input) * factor).toFixed(2), toUnit].join(" ");
}

var milesToKm = converter.curry('km', 1.60936, undefined);
var poundsToKg = converter.curry('kg', 0.45460, undefined);
var farenheitToCelsius = converter.curry('degrees C', 0.5556, -32);

milesToKm(10);            // returns "16.09 km"
poundsToKg(2.5);          // returns "1.14 kg"
farenheitToCelsius(98);   // returns "36.67 degrees C"

curryこれは の拡張に依存してFunctionいますが、ご覧のとおり、使用するのはapply(あまりにも派手なものではありません):

Function.prototype.curry = function() {
    if (arguments.length < 1) {
        return this; //nothing to curry with - return function
    }
    var __method = this;
    var args = toArray(arguments);
    return function() {
        return __method.apply(this, args.concat([].slice.apply(null, arguments)));
    }
}
于 2011-07-28T15:49:08.027 に答える
37

@ハンク・ゲイ

EmbiggensTheMind のコメントに応えて:

カリー化自体が JavaScript で役立つ例は思いつきません。これは、複数の引数を持つ関数呼び出しを、呼び出しごとに 1 つの引数を持つ一連の関数呼び出しに変換する手法ですが、JavaScript は 1 つの関数呼び出しで複数の引数をサポートします。

ただし、JavaScript では (ラムダ計算ではない) 他のほとんどの実際の言語を想定していますが、一般的に部分適用に関連付けられています。John Resigはそれをよりよく説明していますが、要点は、2 つ以上の引数に適用されるいくつかのロジックがあり、それらの引数の一部の値しか知らないということです。

部分的な適用/カリー化を使用して、これらの既知の値を修正し、不明な値のみを受け入れる関数を返し、後で実際に渡したい値を取得したときに呼び出すことができます。これにより、同じ JavaScript ビルトインを同じ値を 1 つだけ指定して何度も呼び出していた場合に、同じことを繰り返さないようにするための便利な方法が提供されます。ジョンの例を盗むには:

String.prototype.csv = String.prototype.split.partial(/,\s*/);
var results = "John, Resig, Boston".csv();
alert( (results[1] == "Resig") + " The text values were split properly" );
于 2008-09-22T09:47:20.220 に答える
8

Hank Gay に同意 - 特定の真の関数型プログラミング言語では非常に便利です - それは必要な部分だからです。たとえば、Haskell では、関数に複数のパラメーターを使用することはできません。純粋な関数型プログラミングでは、これを行うことはできません。一度に 1 つのパラメーターを取り、関数を構築します。JavaScript では、「コンバーター」のような不自然な例にもかかわらず、単純に不要です。カリー化を必要としない、同じコンバーター コードを次に示します。

var converter = function(ratio, symbol, input) {
    return (input*ratio).toFixed(2) + " " + symbol;
}

var kilosToPoundsRatio = 2.2;
var litersToUKPintsRatio = 1.75;
var litersToUSPintsRatio = 1.98;
var milesToKilometersRatio = 1.62;

converter(kilosToPoundsRatio, "lbs", 4); //8.80 lbs
converter(litersToUKPintsRatio, "imperial pints", 2.4); //4.20 imperial pints
converter(litersToUSPintsRatio, "US pints", 2.4); //4.75 US pints
converter(milesToKilometersRatio, "km", 34); //55.08 km

Douglas Crockford が "JavaScript: The Good Parts" で、彼の率直な発言ではなく、カリー化の歴史と実際の使用について何らかの言及をしたことを残念に思います。それを読んでから長い間、私は動揺していましたが、関数型プログラミングを勉強していて、それがどこから来たのかを理解するまで.

もう少し考えた結果、JavaScript でのカリー化の有効な使用例が 1 つあります。それは、JavaScript を使用して純粋な関数型プログラミング手法を使用して記述しようとしている場合です。ただし、まれな使用例のようです。

于 2015-09-03T15:25:47.820 に答える
7

Python に似た関数がfunctools.partialJavaScript でより便利であることがわかりました。

function partial(fn) {
  return partialWithScope.apply(this,
    Array.prototype.concat.apply([fn, this],
      Array.prototype.slice.call(arguments, 1)));
}

function partialWithScope(fn, scope) {
  var args = Array.prototype.slice.call(arguments, 2);
  return function() {
    return fn.apply(scope, Array.prototype.concat.apply(args, arguments));
  };
}

なぜそれを使いたいのですか?thisこれを使用する一般的な状況は、関数を値にバインドする場合です。

var callback = partialWithScope(Object.function, obj);

コールバックが呼び出されると、thisを指しobjます。これは、イベントの状況で、または通常はコードが短くなるため、スペースを節約するのに役立ちます。

カリー化はパーシャルに似ていますが、カリー化が返す関数は引数を 1 つだけ受け入れるという違いがあります (私が理解している限り)。

于 2008-09-22T08:49:04.527 に答える
2

古いスレッドは知っていますが、これが JavaScript ライブラリでどのように使用されているかを示す必要があります。

これらの概念を具体的に説明するために lodash.js ライブラリを使用します。

例:

var fn = function(a,b,c){ 
return a+b+c+(this.greet || ‘'); 
}

部分適用:

var partialFnA = _.partial(fn, 1,3);

カリー化:

var curriedFn = _.curry(fn);

バインディング:

var boundFn = _.bind(fn,object,1,3 );//object= {greet: ’!'}

利用方法:

curriedFn(1)(3)(5); // gives 9 
or 
curriedFn(1,3)(5); // gives 9 
or 
curriedFn(1)(_,3)(2); //gives 9


partialFnA(5); //gives 9

boundFn(5); //gives 9!

違い:

カリー化後、パラメーターが事前にバインドされていない新しい関数を取得します。

部分的な適用の後、いくつかのパラメーターが事前にバインドされた関数を取得します。

バインディングでは、「this」を置き換えるために使用されるコンテキストをバインドできます。バインドされていない場合、関数のデフォルトはウィンドウスコープになります。

アドバイス: 車輪を再発明する必要はありません。部分的なアプリケーション/バインディング/カリー化は非常に関連しています。上記の違いを見ることができます。この意味をどこでも使用すると、人々はあなたが何をしているのかを問題なく認識し、コードの使用を減らす必要があります。

于 2015-07-22T10:39:46.840 に答える
2

これは魔法でもなんでもありません...無名関数の便利な省略形です。

partial(alert, "FOO!")と同等ですfunction(){alert("FOO!");}

partial(Math.max, 0)に対応function(x){return Math.max(0, x);}

部分的な呼び出し ( MochiKitの用語。他のいくつかのライブラリでは、関数に同じことを行う .curry メソッドが提供されていると思います) は、無名関数よりもわずかに見栄えがよく、ノイズが少ないように見えます。

于 2008-09-22T08:46:53.783 に答える
1

JavaScript 関数は、他の関数型言語ではラムダと呼ばれます。別の開発者の単純な入力に基づいて、新しい API (より強力または複雑な関数) を構成するために使用できます。カレーはテクニックの1つにすぎません。これを使用して、単純化された API を作成し、複雑な API を呼び出すことができます。単純化された API を使用する開発者 (たとえば、jQuery を使用して単純な操作を行う) の場合は、カレーを使用する必要はありません。しかし、簡素化された API を作成したい場合は、カレーが役に立ちます。JavaScript フレームワーク (jQuery、mootools など) またはライブラリを作成する必要があります。http://blog.semanticsworks.com/2011/03/enhanced-curry-method.htmlで、強化されたカレー関数を書きました。. カリー化を行うためにカリー メソッドは必要ありません。カリー化に役立つだけですが、関数 A(){} を記述して別の関数 B(){} を返すことにより、いつでも手動でカリー化を行うことができます。さらに興味深いものにするために、関数 B() を使用して別の関数 C() を返します。

于 2011-03-20T18:52:10.900 に答える
1

それを使用するライブラリに関しては、常にFunctionalがあります。

JSでいつ役立つのですか?おそらく他の現代言語でも同じように有用ですが、私がそれを使用しているのは部分的なアプリケーションと組み合わせて使用​​しているのを見ることができる唯一の時間です.

于 2008-09-22T08:26:22.443 に答える
1

おそらく、JS のすべてのアニメーション ライブラリはカリー化を使用していると思います。呼び出しごとに、影響を受ける要素と関数のセットを渡し、要素がどのように動作するかを記述し、すべてのタイミングを保証する高次関数に渡す必要はなく、一般に、パブリック API として顧客がリリースする方が簡単です。 「slideUp」、「fadeIn」のような関数で、要素のみを引数として取り、デフォルトの「アニメーション関数」が組み込まれた高次関数を返すカリー化された関数です。

于 2008-09-22T08:27:38.947 に答える
1

これが例です。

ユーザーが何をしているかを確認できるように、JQuery を使用して一連のフィールドを計測しています。コードは次のようになります。

$('#foo').focus(trackActivity);
$('#foo').blur(trackActivity);
$('#bar').focus(trackActivity);
$('#bar').blur(trackActivity);

(JQuery を使用していないユーザーのために、いくつかのフィールドがフォーカスを取得したり失ったりするたびに、trackActivity() 関数を呼び出したいと言っています。匿名関数を使用することもできますが、複製する必要があります。 4回なので抜き出して名付けました。)

ここで、これらのフィールドの 1 つを別の方法で処理する必要があることがわかりました。これらの呼び出しの 1 つにパラメーターを渡して、追跡インフラストラクチャに渡せるようにしたいと考えています。カレーならできる。

于 2010-07-23T22:01:54.813 に答える
0

最初の引数の値が常に入力される疑似関数を作成することで、ボールを転がしたい場合があることに同意します。幸運なことに、jPaq (h ttp://この機能を提供するjpaq.org/ )。ライブラリの最も優れた点は、必要なコードのみを含む独自のビルドをダウンロードできることです。

于 2011-02-07T16:45:52.020 に答える
0

カレー関数のいくつかのクールなアプリケーションを示す jPaq の例を書きました。ここで確認してください: 文字列関数のカリー化

于 2011-04-07T23:04:47.097 に答える