Currying
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]