JavaScriptにおけるPartialアプリとCurrying
10913 ワード
この文章はメモを勉強しています.JSで勉強している知識点と私の理解点、知識点とテクニック自体は私のオリジナルではありません.(引用または参考にした文章の出所は文末)
Partial Appleication(偏関数アプリケーション)とCurrying(ガリガリ化)の字面の意味を説明しないで、実際の例から始めると便利です.
例えば、function sum(a,b){return a+b}があります.
値を固定したいなら、まずこの値を設定します.
var a=1
sum(a,1) sum(a,100)
または新しい関数function newSum(x){return sum(1,x)}を定義します.
固定値を変更するには、複数の新しい関数を定義する必要があります.
または工場の建設方法function makeSum(n){return function(x){return sum(n+x)} var sum 10=makeSum(10);sum 10(1);
しかし、この工場の方法はsumのロジックしか産出できません.どのようなロジックを入力できる工場が必要ですか?
このように使ってもいいです
function add(a,b){return a+b}
function del(a,b){return a-b;}
var add 10=bindFirstArg(add,10)、add d 10(1)
var del 10=bindFirstArg(del,10);del 10(1);
しかし、変数のパラメータが一つ以上ではなく、個数も一定ではない場合は、どうすればいいですか?
これはいわゆるPartialアプリです.
現在のpartialはパラメータを一次的に統合しています.いくつかのパラメータを固定したいなら、次のように変更できます.
次にCurrryingであり、Partial Appleicationと非常に似ていますが、他の問題を解決するために用いられています.複数の単一パラメータ関数で複数のパラメータ関数をどのように実現しますか?
ここは私の少しの勉強ノートです.知識を共有する先輩と大牛たちに感謝します.彼らの文章の住所は以下の通りです.
http://benalman.com/news/2012/09/partial-application-in-javascript/
http://alecb.me/blog/currying-partial-application/
Partial Appleication(偏関数アプリケーション)とCurrying(ガリガリ化)の字面の意味を説明しないで、実際の例から始めると便利です.
例えば、function sum(a,b){return a+b}があります.
値を固定したいなら、まずこの値を設定します.
var a=1
sum(a,1) sum(a,100)
または新しい関数function newSum(x){return sum(1,x)}を定義します.
固定値を変更するには、複数の新しい関数を定義する必要があります.
または工場の建設方法function makeSum(n){return function(x){return sum(n+x)} var sum 10=makeSum(10);sum 10(1);
しかし、この工場の方法はsumのロジックしか産出できません.どのようなロジックを入力できる工場が必要ですか?
function bindFirstArg(fn,n){// ,
return function(x){
return fn(n,x);
}
}
このように使ってもいいです
function add(a,b){return a+b}
function del(a,b){return a-b;}
var add 10=bindFirstArg(add,10)、add d 10(1)
var del 10=bindFirstArg(del,10);del 10(1);
しかし、変数のパラメータが一つ以上ではなく、個数も一定ではない場合は、どうすればいいですか?
これはいわゆるPartialアプリです.
Partial application can be described as taking a function that accepts some number of arguments, binding values to one or more of those arguments, and returning a new function that only accepts the remaining, un-bound arguments.
簡単に言えば、関数が複数のパラメータの場合、いくつかのパラメータの値を固定したいです.function partial(fn/*,args…..*/){
var args=Array.prototype.slice.call(arguments,1);//arguments , length, , array , this
return function(){
var nargs=Array.prototype.slice.call(arguments,0);// arguments , arguments arguments
fn.apply(this,args.contact(nargs));
}
}
コードは複雑ではありません.使い方は以下の通りです.function sum(){
var args=Array.prototype.slice.call(arguments,0),n=0;
for(var i=0;i<args.length;i++){n+=args[i]}
return i;
}
sum(1,2,3);// , 6
var p=partial(sum,10); p(1,2,3);// 16
このような呼び出しが成功したのはsum関数の内部ではargmentsで着信パラメータを判断していますが、書き込みがないためです.sumがデッドパラメータの個数(function sum(a,b){return a+b}を書くと、問題が発生して、着信パラメータより多くは無視されます.現在のpartialはパラメータを一次的に統合しています.いくつかのパラメータを固定したいなら、次のように変更できます.
var partialAny=(function(){
var slice=Array.prototype.slice;//
partialAny._={};//
return function(fn/*,args…..*/){// return fn partial
var orginArgs=slice.call(arguments,1);//partial
return function(){// return fn ,
var newArgs=slice.call(arguments,0);//
var args=[];
for(var i=0;i<orginArgs.length;i++)
{
args[i]=orginArgs[i]===partialAny._?newArgs.shift():orginArgs[i];
}
return fn.apply(this,args.contact(newArgs));
}
})();
これはちょっと複雑ですが、コメントを見ても分かりやすいです.ここの表示が入れ替わるマーク「.u」はちょっと分かりにくいです.例を見たら分かりやすいです.function hex(r, g, b) { return '#' + r + g + b; }
hex('11', '22', '33'); // "#112233"
var __ = partialAny._;
var redMax = partialAny(hex, 'ff', __, __);
redMax('11', '22'); // "#ff1122"
次にCurrryingであり、Partial Appleicationと非常に似ていますが、他の問題を解決するために用いられています.複数の単一パラメータ関数で複数のパラメータ関数をどのように実現しますか?
Currying can be described as transforming a function of N arguments in such a way that it can be called as a chain of N functions each with a single argument.
つまり、パラメータを受信した後、元の関数が必要な個数を満たしているかどうかを判断します.満足しないと、関数に戻ります.足りないパラメータはまだ入力が必要です.十分であれば、直接元の関数を呼び出します.function curry(fn,n){
if(typeof n !==’number’){n=fn.length;}// ,
function getCurriedFn(prev){
return function(arg){
var args=prev.contact(arg);
if(args.length<n){
return getCurriedFn(args);
}
else{
return fn.apply(this,args);
}
}
}
return getCurriedFn([]);
}
コード自体も分かりやすく、その使い方は以下の通りです.var i = 0;
function a(arg1, arg2, arg3) { return ++i + ': ' + arg1 + ', ' + arg2 + ', ' + arg3; }
// Normal function invocation.
a('x', 'y', 'z'); // "1: x, y, z"
a('x', 'y'); // "2: x, y, undefined"
a('x'); // "3: x, undefined, undefined"
a(); // "4: undefined, undefined, undefined"
// Curried function invocation.
var b = curry(a);
b(); // `a` not invoked, curried function returned
b('x'); // `a` not invoked, curried function returned
b('x')('y'); // `a` not invoked, curried function returned
b('x')('y')('z'); // "5: x, y, z"
b('x')('y')(); // "6: x, y, undefined"
b('x')()(); // "7: x, undefined, undefined"
b()('y')(); // "8: undefined, y, undefined"
b()()('z'); // "9: undefined, undefined, z"
b()()(); // "10: undefined, undefined, undefined”
JS自体は多パラメータ関数をサポートしています.他のいくつかの言語ではHaskellのように、多パラメータ関数はすべて加里化によって実現されます.ここではこのような思想と技術を学習し、理解することができます.学習プログラムの開発には一定の役割があります.ここは私の少しの勉強ノートです.知識を共有する先輩と大牛たちに感謝します.彼らの文章の住所は以下の通りです.
http://benalman.com/news/2012/09/partial-application-in-javascript/
http://alecb.me/blog/currying-partial-application/