javascriptのcurrying関数
6530 ワード
curringの概念は関数プログラミングの概念とデフォルトパラメータと可変パラメータを結合しています.一つの帯域nパラメータ、curriedの関数は固定パラメータとして硬化し、もう一つのバンドn-1パラメータの関数オブジェクトを返します.それぞれLISPの元関数carとcdrの挙動に似ています.curryingは偏関数アプリケーション(partial function aplication,PFA)に一般化され、pという関数は任意の数(順序)のパラメータの関数を残りのパラメータを持つ関数オブジェクトに変換する.
初期のcurry関数は、関数パラメータに従って内部で分岐を選択するという意味です.
if(typeof fun!='function')
throw new Error(「The argment must be a function.」)
)
if(fun.アリティ==0){
throw new Error(「The function must have more than one argment」);
)
var funText=fun.toString()
var args=/function.*(.*)/.exec(funText)[1].split(');
var firstArg=args.shift()
var rertArgs=args.jun(',')
var body=funText.replace(/function.*)/,");
var curriedText=
「function」++firstArg+「」++
「return function」+rertArgs+「」+body+
「③」
eval(「var curried=」+curriedText);
return curried
)
function sum(x,y){
return x+y
)
function mean 3(a,b,c){
return(a+b+c)/3;
)
var a=curry(sum)(10)(15)
alert(a)//25
var b=curry(mean 3)(10)(20,30);
alert(b)//20
var c=curry(curry(sum)(10)(20);
alert(c)
var d=curry(curry(mean 3)(10)(20)(30);
alert(d)
実行コード
続いてクローズドの流行で、行列とアーグメンツの技術を転換する発見、近代的なcurrying関数はついにチョーク登場して、15~17世紀の大航海時代の地理大発見のようで、javascriptの世界は突然に広くなりました.
var reult=0
for(var i=0,n=argments.length;i<n;i++){
result+=argments[i];
)
return relt;
}
var curry=function(fn){/元関数のパラメータは関数です.
return function{/内部関数のパラメータは配列であり、すぐに実行されるので、直接に第三重に行きます.
var self=argments.calee;//自身を保存する
return function(){/これが2回目の呼び出しの関数です.
if(argments.length){//もし追加するパラメータがあれば
[].push.apply(args,argments);
return self(args)
)
else return fn.apply(this,args)//実行
)
}([])
}
var sum 2=curry(sum)
sum 2=sum 2(1)(2)(3)(4)(5);
alert(sum 2();
実行コード
または毎回複数のパラメータが入ってきます.
function sum(){
var reult=0
for(var i=0,n=argments.length;i<n;i++){
result+=argments[i];
)
return relt;
}
var curry=function(fn){/元関数のパラメータは関数です.
return function{/内部関数のパラメータは配列であり、すぐに実行されるので、直接に第三重に行きます.
var self=argments.calee;//自身を保存する
return function(){/これが2回目の呼び出しの関数です.
if(argments.length){//もし追加するパラメータがあれば
[].push.apply(args,argments);
return self(args)
)
else return fn.apply(this,args)//実行
)
}([])
}
var sum 2=curry(sum)
sum 2=sum 2(1,2,3)
sum 2=sum 2(4,5,6)
sum 2=sum 2(7,8,9)
alert(sum 2();
実行コード
上の関数に足りないところがあります.最後にどうしても括弧を入れます.パラメータが十分であれば結果を返します.多くのパラメータは無視したいです.改善は以下の通りです
if(f.length==0)return f;
function iterate(args){
if(args.length)=f.length)
return f.apply(null,args)
return function(){
return iterate(args.co ncat);
}
)
return iterate([])
)
function mean 3(a,b,c){return(a+b+c)/3;
var curriedMean 3=curry(mean 3)
alert(curriedMean 3(1)(2,3);/=>2
alert(curriedMean 3(1)(2)(3);/かっこが無効です
alert(curriedMean 3()(1)()(2)(3));/=>2
alert(curriedMean 3(1,2)(3,4);/=>2(4番目のパラメータは無効)
実行コード
初期のcurry関数は、関数パラメータに従って内部で分岐を選択するという意味です.
//http://www.openlaszlo.org/pipermail/laszlo-user/2005-March/000350.html
// ★★On 8 Mar 2005, at 00:06, Steve Albin wrote:
function add(a, b) {
if (arguments.length < 1) {
return add;
} else if (arguments.length < 2) {
return function(c) { return a + c }
} else {
return a + b;
}
}
var myadd = add( 2 );
var total = myadd(3);
日本の先駆者一人は、アーgmentsをクリアしていなくても、アラyの原生方法で配列に変換することができる場合があります.非常に複雑な正則でevalと現代のcurryingの意味に近い関数を作ります.
function curry(fun) {
if (typeof fun != 'function') {
throw new Error("The argument must be a function.");
}
if (fun.arity == 0) {
throw new Error("The function must have more than one argument.");
}
var funText = fun.toString();
var args = /function .*\((.*)\)(.*)/.exec(funText)[1].split(', ');
var firstArg = args.shift();
var restArgs = args.join(', ');
var body = funText.replace(/function .*\(.*\) /, "");
var curriedText =
"function (" + firstArg + ") {" +
"return function (" + restArgs + ")" + body +
"}";
eval("var curried =" + curriedText);
return curried;
}
function curry(fun){if(typeof fun!='function')
throw new Error(「The argment must be a function.」)
)
if(fun.アリティ==0){
throw new Error(「The function must have more than one argment」);
)
var funText=fun.toString()
var args=/function.*(.*)/.exec(funText)[1].split(');
var firstArg=args.shift()
var rertArgs=args.jun(',')
var body=funText.replace(/function.*)/,");
var curriedText=
「function」++firstArg+「」++
「return function」+rertArgs+「」+body+
「③」
eval(「var curried=」+curriedText);
return curried
)
function sum(x,y){
return x+y
)
function mean 3(a,b,c){
return(a+b+c)/3;
)
var a=curry(sum)(10)(15)
alert(a)//25
var b=curry(mean 3)(10)(20,30);
alert(b)//20
var c=curry(curry(sum)(10)(20);
alert(c)
var d=curry(curry(mean 3)(10)(20)(30);
alert(d)
実行コード
続いてクローズドの流行で、行列とアーグメンツの技術を転換する発見、近代的なcurrying関数はついにチョーク登場して、15~17世紀の大航海時代の地理大発見のようで、javascriptの世界は突然に広くなりました.
// currying
function curry (fn, scope) {
var scope = scope || window;
var args = [];
for (var i=2, len = arguments.length; i < len; ++i) {
args.push(arguments[i]);
};
return function() {
fn.apply(scope, args);
};
}
一般的なcurrying関数は二重しかなく、実行状況は以下の通りです.一回目の実行パラメータは内部関数に戻りきれず、二回目の実行は最終的に完成します.しかし、このパラメータに対しては、いくつかの記事を作成することができます.次の関数を参照してください
function sum(){
var result=0;
for(var i=0, n=arguments.length; i<n; i++){
result += arguments[i];
}
return result;
}
alert(sum(1,2,3,4,5)); // 15
これはいわゆるパラメータ不足問題がなく、一つのパラメータが入ってきても計算されます.パラメータは入ってきませんか?間違いないです.パラメータがあるかどうかが違います.パラメータが存在する場合は常に自己を実行させることができます.最後にパラメータがない場合は、一回だけ実行します.言い換えれば、前のステップはパラメータを格納するためのものである.
var sum2= curry(sum);
sum2= sum2(1)(2)(3)(4)(5);
sum2(); // 15
一般的なcurrying関数よりはちょっと難しいです.コメントを具体的に見る:
var curry= function(fn){//
return function(args){// , ,
//args
var self= arguments.callee;// ( )
return function(){ //
if(arguments.length){//
[].push.apply(args,arguments);//apply args
return self(args);
}else{
return fn.apply(this,args);//apply
}
}
}([]);
};
function sum(){var reult=0
for(var i=0,n=argments.length;i<n;i++){
result+=argments[i];
)
return relt;
}
var curry=function(fn){/元関数のパラメータは関数です.
return function{/内部関数のパラメータは配列であり、すぐに実行されるので、直接に第三重に行きます.
var self=argments.calee;//自身を保存する
return function(){/これが2回目の呼び出しの関数です.
if(argments.length){//もし追加するパラメータがあれば
[].push.apply(args,argments);
return self(args)
)
else return fn.apply(this,args)//実行
)
}([])
}
var sum 2=curry(sum)
sum 2=sum 2(1)(2)(3)(4)(5);
alert(sum 2();
実行コード
または毎回複数のパラメータが入ってきます.
function sum(){
var reult=0
for(var i=0,n=argments.length;i<n;i++){
result+=argments[i];
)
return relt;
}
var curry=function(fn){/元関数のパラメータは関数です.
return function{/内部関数のパラメータは配列であり、すぐに実行されるので、直接に第三重に行きます.
var self=argments.calee;//自身を保存する
return function(){/これが2回目の呼び出しの関数です.
if(argments.length){//もし追加するパラメータがあれば
[].push.apply(args,argments);
return self(args)
)
else return fn.apply(this,args)//実行
)
}([])
}
var sum 2=curry(sum)
sum 2=sum 2(1,2,3)
sum 2=sum 2(4,5,6)
sum 2=sum 2(7,8,9)
alert(sum 2();
実行コード
上の関数に足りないところがあります.最後にどうしても括弧を入れます.パラメータが十分であれば結果を返します.多くのパラメータは無視したいです.改善は以下の通りです
function curry(f) {
if (f.length == 0) return f;
function iterate(args) {
if (args.length <= f.length)
return f.apply(null, args);
return function () {
return iterate(args.concat(Array.prototype.slice.call(arguments)));
};
}
return iterate([]);
}
function curry(f){if(f.length==0)return f;
function iterate(args){
if(args.length)=f.length)
return f.apply(null,args)
return function(){
return iterate(args.co ncat);
}
)
return iterate([])
)
function mean 3(a,b,c){return(a+b+c)/3;
var curriedMean 3=curry(mean 3)
alert(curriedMean 3(1)(2,3);/=>2
alert(curriedMean 3(1)(2)(3);/かっこが無効です
alert(curriedMean 3()(1)()(2)(3));/=>2
alert(curriedMean 3(1,2)(3,4);/=>2(4番目のパラメータは無効)
実行コード