2013-06-30 20 views
4

我有一個搜索名字的函數。這個擴展的`compose`函數有什麼好名字?

我一直在用JavaScript編寫一個new functional programming library,最近我添加了一個對我來說很有用的新函數。我將其命名爲useWith,但我想知道它是否是功能程序員已知的一個以不同名稱命名的函數。

該功能與compose相關,因爲它返回一個新功能,它組合了幾個現有功能,但方式與compose略有不同。它收到的第一個參數被單獨列出;其餘部分統一處理。當調用返回的函數時,參數將分別傳遞給其餘的每個函數,並且結果以及任何不成對的參數都會發送到第一個函數,然後返回結果。因此,如果只用兩個函數調用它,並且如果傳遞的結果函數只有一個參數,這完全等同於compose。但它有多個參數的其他功能。

我想這個功能的原因是,我正在實施類似的project功能 米哈爾Fogus在Functional Javascript介紹,Codd的project的類似JavaScript對象的數組等價物,且類似於SQL的select動詞。這是很容易這樣寫:

var project = curry(function(keys, table) { 
    return map(pick(keys), table); 
}); 


// Used like this: 
var kids = [{name: 'Bob', age: 3, eyes: 'blue', hair: 'brown'}, 
      {name: 'Sue', age: 5, eyes: 'hazel', hair: 'blonde'}]; 
project(['name', 'eyes'], kids); 
//=> [{name: 'Bob', eyes: 'blue'}, {name: 'Sue', eyes: 'hazel'}] 

但我真的想實現它在一個無點的風格。但當然,這是行不通的:

var project = compose(map, pick); // NO! 

...因爲沒有工具穿過第二個參數,tablecompose

這就是這個新功能進來:

var project = useWith(map, pick); 

我把它比這種情況更通用,雖然。原始方法被稱爲using,參數相反,因此它讀作一個命令:「使用選擇,映射」。但是這使得很難擴展到多個參數。我必須將第一個數組作爲一個數組,或者讓它成爲一個數組或單個函數,而我真的不想去那裏。這似乎是一個更好的解決方案。

我感覺好像我不能成爲第一個需要像這樣的功能的人。這是FP語言中的常見模式嗎?這個功能有一個共同的名字嗎?如果沒有,是否有比useWith更好的名字?


如果你很好奇,這裏的useWith實施,使用很明顯slice,並且比較規範的curry

由於缺乏JavaScript的知識
var useWith curry(function(fn /*, tranformers */) { 
    var tranformers = slice(arguments, 1); 
    return function() { 
     var args = [], idx = -1; 
     while (++idx < tranformers.length) { 
      args.push(tranformers[idx](arguments[idx])) 
     } 
     return fn.apply(this, args.concat(slice(arguments, tranformers.length))); 
    }; 
}); 
+0

我會說當'compose'將結果函數的所有參數提供給'pick'時,'compose(map,pick)'只是一個* NO * - 它不一定應該。如果你採用嚴格的固定版本(比如Haskell''。),它實際上是有效的。 – Bergi

+0

@Bergi:是的,我花了一段時間才意識到它不會在Javascript的動態函數中起作用。我撓了一下頭,不能看出這個優雅的小代碼有什麼問題! :-)我試圖決定是否要以能夠解決此問題的方式更改「撰寫」。現在,它把所有的論點弄糊塗了,把第一個調用和後面的調用區別開來,顯然只有一個參數。 –

+0

我認爲既不對也不對。絕對值得研究函數組合(以及類似的函數方法)如何在可變參數函數(以及實現存在的可能性)上如何工作,併爲它們找到標準術語。 – Bergi

回答

4

我可能誤解的東西,但如果map是一個curried函數,並且compose返回一個curried函數,則compose(map, pick)project,因爲map部分應用於pick - 部分應用程序僅適用於第一個參數。這裏是我的意思的證明:

compose map pick = 
(\f g x. f (g x)) map pick =   -- definition of compose 
(\g x. map (g x)) pick =    -- apply to map 
\x. map (pick x) =     -- apply to pick 
\x. (\y. map (pick x) y) =   -- eta-expansion of inner function 
\key table. map (pick key) table  -- combine and rename 

(我假設你知道基於庫的名稱演算。)

正如你所看到的,這不取決於map的元數 - 你可以隨心所欲的擴展,因此,泛化不需要額外的工作。只要一切都是咖喱。

對於具有混合性,咖喱味和不安全性的功能,像these這樣的組合器,但這可能有點太過分了。

+0

我撰寫的版本是兩種方式的動態元素。首先它組成了一個任意的函數序列。其次,結果函數將其所有參數輸入鏈中的第一個函數。第二個屬性是干擾這裏的。 (順便說一下,我可以閱讀lambda表達式,儘管我的ramda和eweda庫名稱大多是一個笑話。)我也會看看這個鏈接。感謝您的解釋。我**知道**我並不太瘋狂! –