Table of contents


柯里化(currying)是指把多個參數的單一function轉換成只使用單一參數多個functions,轉換的方式,是把參數折分後,將前一個function的執行結果傳入下一個function, 功能上的作用是讓每個function都只有一個參數,而實際上的運用是用來

// this code taken from http://www.codecommit.com/blog/scala/function-currying-in-scala
def add(x:Int, y:Int) = x + y
 
add(1, 2)   // 3
add(7, 3)   // 10
 
// currying版的
 
def add(x:Int) = (y:Int) => x + y
 
add(1)(2)   // 3
add(7)(3)   // 10

以 x = 1, y =2為例

第一個版本的add function,是add接受兩個參數(x=1,y=2),然後相加後得到結果3

第二個柯里化後的add function,是第一個function add(x:Int), add(1)執行後會傳回一個整數值1,然後執行的結果1當作輸入值傳到第二個function(y:Int) ⇒ x + y, (這個是一個closure,因為他有一個free variable x),x=1(來自前一個function的執行結果),y=2可得執行結果為3

The Power of Currying

scala為什麼需要Currying這樣的語法?因為有了Currying可以讓程式更一般化(更抽象,更通用)

// this code taken from http://www.codecommit.com/blog/scala/function-currying-in-scala
 
def process[A](filter:A=>Boolean)(list:List[A]):List[A] = {
  lazy val recurse = process(filter) _
 
  list match {
    case head::tail => if (filter(head)) {
      head::recurse(tail)
    } else {
      recurse(tail)
    }
 
    case Nil => Nil
  }
}
 
val even = (a:Int) => a % 2 == 0
 
val numbersAsc = 1::2::3::4::5::Nil
val numbersDesc = 5::4::3::2::1::Nil
 
process(even)(numbersAsc)   // [2, 4]
process(even)(numbersDesc)  // [4, 2]

最後面的

process(even)(numbersAsc)   // [2, 4]
process(even)(numbersDesc)  // [4, 2]

process(even)像這樣的使用方式,如果一直在程式出現,在imperative language(命令式語言 ex:java)中,我們通常會把這個透過extract method的重構手法,把它抽出成一個獨立的method, 那在scala中,可以把process(even)變成Partially Applied Functions(在此例中為val processEvens = process(even) _),然後,直接使用processEvens會將原來process(even)變成Currying後的第一個 function的傳回值

// this code taken from http://www.codecommit.com/blog/scala/function-currying-in-scala
 
val even = (a:Int) => a % 2 == 0
val processEvens = process(even) _
 
val numbersAsc = 1::2::3::4::5::Nil
val numbersDesc = 5::4::3::2::1::Nil
 
processEvens(numbersAsc)   // [2, 4]
processEvens(numbersDesc)  // [4, 2]

Resources