javascriptのcurrying関数

6530 ワード

curringの概念は関数プログラミングの概念とデフォルトパラメータと可変パラメータを結合しています.一つの帯域nパラメータ、curriedの関数は固定パラメータとして硬化し、もう一つのバンドn-1パラメータの関数オブジェクトを返します.それぞれLISPの元関数carとcdrの挙動に似ています.curryingは偏関数アプリケーション(partial function aplication,PFA)に一般化され、pという関数は任意の数(順序)のパラメータの関数を残りのパラメータを持つ関数オブジェクトに変換する.
初期の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番目のパラメータは無効)
実行コード