在 「徹底」函數式編程 一文中,咱們初步感覺了函數式編程的力量:以很是簡潔的代碼,經過組合任何短小的簡單函數,實現更加複雜功能的複合函數。html
有小夥伴可能會問: 既然函數是這麼重要的原材料,那麼從哪裏能夠獲取這麼多原材料呢 ?總不成,一個個去定義吧。別急,Curry 提供了批量生產函數的能力,—— 若是星雲是恆星的工廠,那麼,Curry 就是函數的工廠。編程
本文將以 Groovy 爲示例,講解 Curry 的特性及能力。
框架
小夥伴都學過多元函數,好比 f(x,y) = x^2 + y ,當 y = 0 時,就變成 f(x) = x^2 平方函數; 當 x = 1 時,就變成 f(y) = 1+y 線性函數。 Curry ,通俗地說,就是將多變量的函數,經過逐個因變量賦值,從而批量生成函數的能力。函數式編程
以下代碼所示: def closure = { x,y -> x^2 +y } 定義了一個二元函數 f(x,y) , rcurry(0) 便是將 y 賦值爲 0 (右邊的參數),這樣就獲得了一元函數 square(x) = x^2 ; curry(1) 便是將 x 賦值爲 1 (默認是左邊的參數),就獲得了 linear(y) = 1+y 。 嗯,就是這麼簡單。函數
class Basics { static void main(args) { def closure = { x,y -> x * x +y } def square = closure.rcurry(0) println((1..5).collect { square(it) }) def linear = closure.curry(1) println((1..5).collect { linear(it) }) } }
輸出結果:this
[1, 4, 9, 16, 25] [2, 3, 4, 5, 6]
那麼 Curry 有什麼實際應用呢 ? 總不能只停留在數學的領域裏。 實際上 Curry 的能力很是強大。咱們來實現一個通用調用器。在實際工程中,經常須要調用具備相同參數的函數,或者對不一樣的對象進行相同的處理。code
假設有兩個訂單處理函數: cancel, complete ,有一個列表排序函數 sort:htm
def static sort(list) { list.sort() return list } def static cancel(order) { println ("cancel: " + order.orderNo) } def static complete(order) { println ("complete: " + order.orderNo) } class OrderParam { def orderNo def shopId }
能夠定義一個二元函數 generalCaller ,能夠對指定的參數對象 param 使用指定的 handler 進行處理。對象
def generalCaller = { param, handler -> handler(param) }
如今,來看怎麼使用:blog
第一種方式:指定參數對象。 能夠構造一個訂單對象,使用 Curry ,就獲得了能夠處理這個訂單的函數處理器 orderProcessor, 而後就能夠傳入不一樣的訂單處理器進行處理。this.&method 是 Groovy 對函數的引用。
def orderProcessor = generalCaller.curry(new OrderParam(orderNo: 'E0001', shopId: 55)) orderProcessor(this.&cancel) orderProcessor(this.&complete)
第二種方式,指定處理器。 就獲得了一個對參數進行排序的函數 sort(param) , 而後傳入不一樣的可排序對象進行處理:
def sorter = generalCaller.rcurry(this.&sort) println sorter([4,7,2,6,1,3]) println sorter(["i", "have", "a", "dream"])
是否是很是靈活 ? 在 「函數柯里化(Currying)示例」 一文中,使用 Curry 實現了一個簡易的文件處理框架。
Curry 能夠將高維函數逐步降維,批量生成大量的低維函數。 若是有一個 N 維函數,思考下,經過 Curry ,能夠生成多少個低維函數 ?Curry 結合函數式編程,蘊藏着驚人的潛力。