2011-03-11 34 views
8

我正在嘗試創建curry function,它可以應用於任何函數並返回另一個函數,並應用一個參數。 屬性,我想有:javascript currying

  1. 如果函數只有一個參數,咖喱函數返回值: F(一);咖喱(f,x)= f(x);
  2. 如果函數有很多參數currey應該重試curry函數: g(a1,a2,..,aN);咖喱(g,x)= g2(a2,..,aN):g2(a2,.. aN)= g(x,a2,...,aN)
  3. curry函數的長度運算應該「需要」 g.length = N =>咖喱(G,X)。長度= N-1

有一個在原型框架咖喱和討論在one blog的一些實施方式。但是這個實現並不好,因爲它對於只有一個參數(1)的函數不起作用,並且返回的函數'length'屬性爲0(3)。

針對第一屬性有一個簡單的實現:

function curry(f,x) { 
    if (f.length == 1) return f(x); 
    ... 
} 

但我不知道如何與第三規則的工作,即函數可以作爲constucted內部函數,因爲會有一個嵌套詞法環境和將能夠使用f:

function curry(f,x) { 
    return function() { ... } 
} 

但在這種情況下,我將不再能夠明確地設置參數。 在另一方面功能可與「新功能」的語句來構建,水木清華這樣的:

function curry(f,x) { 
    var args = []; 
    for (var i=1; i<f.length; i++) { 
     args.push('a'+i); 
    } 
    var sa = args.join(); 
    return new Function(sa,"return f(x,"+sa+")"); 
} 

但在這種情況下,f和X將未綁定的,因爲匿名函數將在 全球詞法環境中創建。

所以問題:

  1. 有沒有辦法與功能關鍵字生成功能時,明確地設置參數算什麼?
  2. 有沒有一種方法可以設置使用'new Function'語句創建的函數環境?
  3. 我們有辦法以任何其他方式解決我的問題嗎?
+1

僅僅因爲一個函數被*聲明爲一個參數並不意味着它不會*接受*更多。 – Pointy 2011-03-11 13:41:47

+1

我發現第一個要求不對稱。在一個參數中捲曲一個函數應該返回一個沒有參數的函數,在我看來... – 6502 2011-03-11 13:53:02

+0

我知道如果函數聲明一些參數它可以接受更多,但無論如何,可能會有一種情況,當我想檢查長度屬性和解決方案將打破這一邏輯。 1和2問題沒有答案,但核心問題解決了,所以我把問題標記爲已解決 – qnikst 2011-03-11 17:11:59

回答

6

Functional庫實現它是採取傳遞的參數爲「咖喱()」作爲第一參數傳遞的方式。 「curry」操作的函數結果將在調用時傳入其他參數,並在參數列表的處添加它們。它根本不擔心參數列表的長度,因爲這通常不是JavaScript中的一個固定的東西,所以沒有任何意義。

這樣:

var curry = myFunction.curry("Tuesday", x + y); 

所以美其名曰:

curry(100, true); 

會就像調用:

myFunction("Tuesday", x + y, 100, true); 

功能有一個稱爲 「局部()」 的另一個功能,它允許更多控制參數替代。當調用「部分()」,你在虛擬的參數傳遞(「_」)來表示,其中「洞」是在參數列表:

var partialFunc = myFunction.partial("Tuesday", _, 100, true, _, "banana"); 

這兩個「_」參數意味着由此產生的「 partialFunc」應該放棄傳遞給它的前兩個參數爲這些插槽參數列表:

partialFunc(x + y, "Texas"); 

因此,就像調用:

myFunction("Tuesday", x + y, 100, true, "Texas", "banana"); 

我衷心建議得到了圖書館和看代碼參與其中。令人驚訝的是,它簡潔明瞭。

還有一件事:重要的是要注意,因爲JavaScript不是懶惰的評估語言,所以這不是像在Haskell這樣的懶惰函數語言中的「咖喱」操作。區別在於,「咖喱時間」的參數是評估爲,因此排序 - 「熟」到結果中。用懶惰的語言,事情是不同的。

3
function curry(fn, args) { 
    // no need to var these, they are scoped via argument list - we overwrite them 
    // convert the arguments to a real array: 
    args = [].slice.apply(arguments); 
    // first argument is a function: 
    fn = args.shift(); 
    return function() { 
    // get internal args 
    var iArgs = [].slice.apply(arguments); 
    // apply curried arguments, then our arguments: 
    return fn.apply(this, args.concat(iArgs)); 
    } 
} 

function add(a,b) { return a+b; } 
var add2 = curry(add, 2); 
alert(add2(5)); //7 

var hello = curry(add, "Hello "); 
alert(hello("World!")); 
2

多年來我一直使用的函數原型咖喱,看起來像這樣:

Function.prototype.curry = function curry() { 
    var fn = this, args = Array.prototype.slice.call(arguments); 
    return function curryed() { 
     return fn.apply(this, args.concat(Array.prototype.slice.call(arguments))); 
    }; 
}; 

也許這將滿足您的需求也是如此。

您只需使用它像這樣:

function fn1(arg1,arg2) { /*...*/ } 

var fn1Curried = fn1.curry('whatever'); //sets arg1 

它將與任意數量的參數工作。

0
function curry(func) { 
    var initial_args = [].slice.apply(arguments, [1]); 
    var func_args_length = func.length; 

    function curried(args) { 
     if (args.length >= func_args_length) { 
      return func.apply(null, args); 
     } 

     return function() { 
      return curried(args.concat([].slice.apply(arguments))); 
     }; 
    } 

    return curried(initial_args); 
}