1、初識Currying柯里化
柯里化(Currying)技術 Christopher Strachey 以邏輯學家 Haskell Curry 命名的(儘管它是 Moses Schnfinkel 和 Gottlob Frege 發明的)。它是
把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,而且返回接受餘下的參數且返回結果的新函數的技術。
簡單理解就是改變函數的表達形式但其功能特性不變,這對於第一次接觸柯里化的人來說,這樣的一個技術貌似有點「雞肋」,但若是你有豐富的JS編程經驗的話,相信就必定會感覺到柯里化實際上是具備很高的實用性的。不管是在提升適用性仍是在延遲執行或者固定易變因素等方面,柯里化技術都發揮着重要的做用。
2、從案例角度學習scala柯里化
仍是老觀點——不管是修煉新技術仍是舊理論,結合小案例理解學習,纔是最有效的方法。下面將經過幾個例子來學習scala柯里化。
2.一、從2個整數相乘運算的函數來揭開柯里化的神祕面紗
在scala中定義2個整數相乘運算的函數是很是簡單的,具體以下:
def multiplie2par(x:Int,y:Int)=x*y
使用柯里化技術能夠將上述2個整數的乘法函數改修爲接受一個參數的函數,只是該函數返回是一個以原有第二個參數爲參數的函數。
def multiplie1par(x:Int)=(y:Int)=>x*y
【ps說明:multiplie1par(x:Int)爲接收一個參數的新等價函數,(y:Int)=>x*y則是新等價函數的返回體,它自己就是一個函數(嚴格來講應該是一個匿名函數),參數爲除等價新函數的參數外原函數剩餘的參數。】
上述使用柯里化技術獲得等價新函數,在scala語言中看起來還不是很簡潔,在scala中能夠進一步簡化爲:
def multiplie1par1(x:Int)(y:Int)=x*y
編譯運行的結果以下:
一樣對於三個整數乘法的函數在scala中因爲有柯里化的存在,天然有多種功能等價的函數定義形式,如如下四種函數都是實現了三個整數乘法功能,只不過調用不一樣形式參數過程略有不一樣,直接參入三個參數的一步到位就能夠獲得運算結果,而傳入1或者2個參數的須要分步驟再傳入第2/3或者第3個參數才能求出三個整數相乘的結果,很好地體現了延遲執行或者固定易變因素等方面能力。
def multiplie3par(x:Int,y:Int,z:Int)=x*y*z
def multiplie3par1(x:Int)=(y:Int,z:Int)=>x*y*z
def multiplie3par2(x:Int)(y:Int)(z:Int)=x*y*z
def multiplie3par3(x:Int)(y:Int)=(z:Int)=>x*y*z
編譯執行的結果都是同樣
2.二、scala中柯里化的另外一種典型案例——correspondsf方法的柯里化應用
在scala中corresponds方法能使得兩個序列按照必定的條件進行比較,該方法其實也是通過柯里化參數的。在scala的API中該方法定義以下:在方法簽名描述中有兩個參數,that序列和p函數,其中p函數有兩個參數,第二個參數類型是與that序列一致的。應用柯里化,咱們能夠省去第二個參數中B的類型,由於從that序列中推斷出B的類型。
def corresponds[B](that: GenSeq[B])(p: (T, B) ⇒ Boolean): Boolean
所以假若有字符串類型序列a和字符串序列b,咱們可使用a. corresponds(b)(_. equalsIgnoreCase(_))來判斷兩個字符串序列在不區分大小的狀況是否一致,這就爲編程帶來了「魔法般」的靈活性。
3、總結柯里化的做用
3.一、柯里化技術在提升適用性仍是在延遲執行或者固定易變因素等方面有着重要重要的做用,加上scala語言自己就是推崇簡潔編碼,使得一樣功能的函數在定義與轉換的時候會更加靈活多樣。另外在Spark的源碼中有大量運用scala柯里化技術的狀況,須要掌握好該技術才能看得懂相關的源代碼。
3.二、在scala柯里化中,閉包也發揮着重要的做用。所謂的閉包就是變量出了函數的定義域外在其餘代碼塊還能其做用,這樣的狀況稱之爲閉包。就上述討論的案例而言,若是沒有閉包做用,那麼轉換後函數其實返回的匿名函數是沒法在與第一個參數x相關結合的,天然也就沒法保證其所實現的功能是跟原來一致的。