2012-03-28 41 views
3

(真的strugging所有權這個問題,因此,如果任何人有意見了自由。)當在underscore.js中鏈接操作(如map reduce)時,有沒有提供最終轉換方法的方法?

說我想要做這樣的操作:

  • 採取數組[1,2,3]
  • 由2(地圖)乘以每個元素:[2,4,6]
  • 添加元素一起(減少):120
:12
  • 乘以10的結果

    我可以在下劃線使用鏈接做到這一點很乾淨,像這樣:

    arr = [1,2,3] 
    map = (el) -> 2*el 
    reduce = (s,n) -> s+n 
    out = (r) -> 10*r 
    
    reduced = _.chain(arr).map(map).reduce(reduce).value() 
    result = out(reduced) 
    

    但是,如果我能鏈中的「出」的方法也一樣,這樣的話會更好:

    result = _.chain(arr).map(map).reduce(reduce).out(out).value() 
    

    現在這將是一個相當簡單的補充庫,如下劃線。但我的問題是:

    • 此'out'方法在函數式編程中有一個名稱嗎?
    • 這是否已經存在於下劃線(tap接近,但不完全)。
  • +0

    您是否看到此線程https://github.com/documentcloud/underscore/pull/499?如果你有一個很好的現實世界的例子,你可以試着問Jeremy爲什麼他這個拉請求是不合適的。 – Karolis 2012-03-28 21:52:38

    +0

    什麼是' - >'語法? – Marcin 2012-04-23 17:40:27

    +0

    Hi @Marcin,道歉,那就是CoffeeScript。 '(r) - > 10 * r'與'function(r){return 10 * r; }' – latentflip 2012-04-24 09:15:31

    回答

    3

    這個問題讓我頗感興趣。這是我的一些想法。

    感覺就像在'chain()模式中使用underscore.js'脫離了函數式編程範例。基本上,不是在函數上調用函數,而是以OOP方式調用包裝對象實例的方法。

    我自己在這裏和那裏使用underscore's chain(),但這個問題讓我想到了。如果最好簡單地創建更有意義的函數,然後可以按順序調用,而不必使用chain()。然後,您的例子是這個樣子:

    arr = [1,2,3] 
    double = (arr) -> _.map(arr, (el) -> 2 * el) 
    sum = (arr) -> _.reduce(arr, (s, n) -> s + n) 
    out = (r) -> 10 * r 
    
    result = out sum double arr 
    # probably a less ambiguous way to do it would be 
    result = out(sum(double arr)) 
    

    在真正的函數式編程語言展望(如..不是JavaScript更多功能),似乎你可以做完全有同樣的事情在一個更簡單的方式。這是用標準ML編寫的相同程序。請注意,只有一個參數調用map會返回另一個函數。沒有必要像在JavaScript中那樣將這個映射封裝在另一個函數中。

    val arr = [1,2,3]; 
    val double = map (fn x => 2*x); 
    val sum = foldl (fn (a,b) => a+b) 0; 
    val out = fn r => 10*r; 
    
    val result = out(sum(double arr)) 
    

    標準ML還允許您創建運營商,這意味着我們可以作出這樣可以用來調用這些函數以更直觀的順序有點「鏈」操作。

    infix 1 |>; 
    fun x |> f = f x; 
    
    val result = arr |> double |> sum |> out 
    

    我也覺得這underscore.js鏈具有類似於函數式編程單子的東西,但我不知道很多關於這些。儘管如此,我感覺這種數據處理流水線並不是您通常使用monads來處理的東西。

    我希望具有更多功能編程經驗的人可以切入並糾正我,如果我在上面的任何一點上都錯了。

    UPDATE

    略有下車的話題,但一個的方式創造的部分功能可能是以下幾點:

    // extend underscore with partialr function 
    _.mixin({ 
        partialr: function (fn, context) { 
        var args = Array.prototype.slice.call(arguments, 2); 
        return function() { 
         return fn.apply(context, Array.prototype.slice.call(arguments).concat(args)); 
        }; 
        } 
    }); 
    

    此功能現在可以用於從任何下劃線函數創建一個部分功能,因爲他們大多數將輸入數據作爲第一個參數。例如,SUM函數現在可以像

    var sum = _.partialr(_.reduce, this, function (s, n) { return s + n; }); 
    sum([1,2,3]); 
    

    我還是喜歡創建ARR |>雙|>和|>出過了(SUM(雙(ARR)))雖然。 Underscore的鏈()很好,因爲它讀取更自然的順序。

    +0

    Cheers @Karolis,很好的發現我的方法並沒有實際的功能,因爲是的,即使是文檔調用'chain()模式'使用下劃線的OO方式。 – latentflip 2012-03-28 22:29:04

    +0

    我更喜歡你的新方法。好想法:) – latentflip 2012-03-28 22:33:15

    +0

    我希望創建這些小功能的想法更容易。特別是在vanilla JavaScript中,寫入像(arr) - > _.map(arr,(el) - > 2 * el)這樣的smr有點冗長。我正在研究如何_.compose或_.bind或部分或咖喱可以幫助,但不能完全釘它.. – Karolis 2012-03-28 22:47:11

    2

    就您所尋找的名稱而言,我認爲您所要做的僅僅是一種函數應用程序的形式:您有一個下劃線對象,並且您希望將函數應用於其值。在下劃線,你可以將其定義是這樣的:

    _.mixin({ 
        app: function(v, f) { return f (v); } 
    }); 
    

    ,那麼你幾乎可以做你的要求爲:

    var arr = [1,2,3]; 
    function m(el) { return 2*el; }; 
    function r(s,n) { return s+n; }; 
    function out(r) { return 10*r; }; 
    
    console.log("result: " + _.chain(arr).map(m).reduce(r).app(out).value())); 
    

    說了這麼多,我想使用類似SML使傳統的類型化函數式編程語言這種想法很多,爲功能組合提供了更輕量級的語法。 Underscore在函數式編程方面做了一些jquery轉換,我不確定我在想什麼;但沒有靜態類型的檢查,很容易犯錯誤!

    相關問題