+
1
|
skin
|
login
|
edit
workshop
::
curry
user:anonymous
_h1 curry {sup (or partial application)} _p « Currying is the process of turning a function that expects multiple parameters into one that, when supplied fewer parameters, returns a new function that awaits the remaining ones. » ([[source|http://fr.umio.us/favoring-curry/]]) (Some will insist that what we're doing is more properly called "partial application", and that "currying" should be reserved for the cases where the resulting functions take one parameter, each resolving to a separate new function until all the required parameters have been supplied. They can please feel free to keep on insisting.) _ul See [[currying-vs-partial-application|http://www.datchley.name/currying-vs-partial-application/]] _h3 1) with javascript {script function add (a,b,c){ if (arguments.length < this.add.length) { return curry(this.add,arguments,this); } return a+b+c; } function curry(func,args,space) { var n = func.length - args.length; var sa = Array.prototype.slice.apply(args); function accumulator(moreArgs,sa,n) { var saPrev = sa.slice(0); var nPrev = n; for(var i=0;i < moreArgs.length;i++,n--) { sa[sa.length] = moreArgs[i]; } if ((n-moreArgs.length) <= 0) { var res = func.apply(space,sa); sa = saPrev; n = nPrev; return res; } else { return function (){ return accumulator(arguments,sa.slice(0),n); } } } return accumulator([],sa,n); } function run() { getId('output').innerHTML = 'add(1,2,3) = ' + add(1,2,3) + '\n(add(1))(2,3) = ' + (add(1))(2,3) + '\n(add(1,2))(3) = ' + (add(1,2))(3) + '\n((add(1))(2))(3) = ' + ((add(1))(2))(3); } setTimeout( run, 10 ); } {pre {@ id="output"}} _p In javascript, functions need some helper function to be curried. The code isn't straightforward: {pre °° function add (a,b,c){ if (arguments.length < this.add.length) { return curry(this.add,arguments,this); } return a+b+c; } function curry(func,args,space) { var n = func.length - args.length; var sa = Array.prototype.slice.apply(args); function accumulator(moreArgs,sa,n) { var saPrev = sa.slice(0); var nPrev = n; for(var i=0;i < moreArgs.length;i++,n--) { sa[sa.length] = moreArgs[i]; } if ((n-moreArgs.length) <= 0) { var res = func.apply(space,sa); sa = saPrev; n = nPrev; return res; } else { return function (){ return accumulator(arguments,sa.slice(0),n); } } } return accumulator([],sa,n); } °°} _h3 2) with lambdatalk _p In lambdatalk functions don't know [[closure]] but are de facto curried. The code is straightforward, just define the function as usual: {pre '{def add {lambda {:a :b :c} {+ :a :b :c} }} -> {def add {lambda {:a :b :c} {+ :a :b :c}}} } _p And use it: {pre '{add 1 2 3} -> {add 1 2 3} '{{add 1} 2 3} -> {{add 1} 2 3} '{{add 1 2} 3} -> {{add 1 2} 3} '{{{add 1} 2} 3} -> {{{add 1} 2} 3} } _p The partial call {b '{add 1}} returns {b {{add 1} 2string}} where {code :a} has been replaced by {b 1}. And so on. _p This is how currying is coded in the function handling {b lambdas} >>> {note_start lambda {b code}}. {note_end {@ id="lambda"} {pre °° var eval_lambda = function(s){ s = eval_lambdas( s ); var index = s.indexOf('}'), args = supertrim(s.substring(1, index)).split(' '), body = s.substring(index+2).trim(), name = 'lambda_' + g_lambda_num++; for (var reg_args=[], i=0; i < args.length; i++) reg_args[i] = RegExp( args[i], 'g'); // args become regexps dict[name] = function() { var vals = supertrim(arguments[0]).split(' '); return function(bod) { if (vals.length < args.length) { // 1) number of values < arity -> partial application -> create a lambda for (var i=0; i < vals.length; i++) bod = bod.replace( reg_args[i], vals[i] ); var _args = args.slice(vals.length).join(' '); bod = '{' + _args + '} ' + bod; bod = eval_lambda( bod ); } else { // 2) number of values === arity -> create a form to be evaluated for (var i=0; i < args.length; i++) bod = bod.replace( reg_args[i], vals[i] ); } return bod; }(body); }; return name; }; °°} } _p Some people think that [[closure]] is mandatory for currying. Lambdatalk demonstrates that partial application can be easily achieved without closure and compensates rather well the lack of closure. _p For instance {b pairs}: {code [cons, car, cdr]} structures are given as primitive functionalities in lambdatalk. But they could be easily defined as user functions: {pre '{def kons {lambda {:a :b :m} {{:m :a} :b}}} -> {def kons {lambda {:a :b :m} {{:m :a} :b}}} '{def kar {lambda {:p} {:p {lambda {:x :y} :x}}}} -> {def kar {lambda {:p} {:p {lambda {:x :y} :x}}}} '{def kdr {lambda {:p} {:p {lambda {:x :y} :y}}}} -> {def kdr {lambda {:p} {:p {lambda {:x :y} :y}}}} '{kar {kons A B}} -> {kar {kons A B}} '{kdr {kons A B}} -> {kdr {kons A B}} } _p Without closure! _p See also [[oxford_slides]].