Currying這個特性,根據Wikipedia的解釋,是指將多個參數的方法,轉換成只有一個參數的方法(其他參數將另外指定).看起來很玄,一個簡單的範例(出自http://www.codecommit.com/blog/scala/function-currying-in-scala)像這樣.
- 非Currying
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 |
- 更簡略的寫法
def add_(x: Int)(y: Int) = x + y add_(7)(3) //10
透過這樣的寫法,可以讓每個方法更容易被其他方法所使用.
來看看以下這些範例,可以猜到結果會是如何嗎?
def add_7(x: Int) = add(7)(x) add_7(3) def add_7_1(x: Int) = add(7) add_7_1(3) def add_7_2 = add(7) add_7_2(3)
其實我也不是很熟語法細節,只能靠實作來理解,以下是解答:
def add_7(x: Int) = add(7)(x) add_7(3)
// add_7[](val x: Int) => Int
// res1: Int =10 def add_7_1(x: Int) = add(7) add_7_1(3) // add_7_1[](val x: Int) => Int => Int
// res2: Int => Int => <function> def add_7_2 = add(7) add_7_2(3)
// add_7_2[] => Int => Int
// res3: Int = 10
- 第一個add_7,吃一個Int(x),實作時會將他傳給定義中的(x),而(x)為add_7的第二個參數.
- 第二個add_7_1,也是吃一個Int(x),雖然看起來跟第一個很像,但是實作時,x 傳不到等號右邊的定義裡(因爲沒有同名為x的參數);而add(7)雖然有給第一個參數,但是實作時沒有第二個參數,所以跑不出結果.
- 第三個add_7_2,沒有設定參數,所以是沿用原本add的參數,因此實作時的參數(3),會直接傳給add(7),變成add(7)(3),跑出正確結果.
這是簡單的例子,稍微瞭解一下何謂Currying的概念,接著透過官網的例子,看一個比較複雜的應用(http://docs.scala-lang.org/tutorials/tour/currying.html)
def filter(xs: List[Int], p: Int => Boolean): List[Int] = if (xs.isEmpty) xs else if (p(xs.head)) xs.head :: filter(xs.tail, p) else filter(xs.tail, p)
def modN(n: Int)(x: Int) = ((x % n) == 0)
val nums = List(1, 2, 3, 4, 5, 6, 7, 8)
println(filter(nums, modN(2))) //List(2, 4, 6, 8) println(filter(nums, modN(3))) //List(3, 6)
這個例子我真的看超久的,五行code看了快一小時吧Orz
這個例子有兩個方法:
- modN:是一currying的方法,吃兩個變數n和x,方法會透過 (x % n == 0)這個邏輯判斷,吐回一個Boolean值.
- filter:主要的方法,吃一個List(xs)和一個function(p),這個function會吃Int然後吐出Boolean值.內容會去將List的第一個數(xs.head),傳到function(p)中,判斷是否為真,如果為真,會將xs.head,接到(::)後面的陣列.這個方法難懂得在於,這邊還有使用遞迴的技巧.後面的陣列(filter( xs.tail, p)是一個遞迴函數,將剛剛除了xs.head,剩下的陣列(xs.head),又放回filter中再做一次篩選.
- 最後來看如何使用這兩個函數:filter(nums, modN(2)),filter第一個參數吃的是陣列,沒有問題.接著吃的函數為modN(2)這個currying函數.先前提到Currying函數的特色就是將多個參數轉成單一參數的函數.原本modN有(n)和(x)兩個函數.在帶入filter時,modN(2)代表了modN(2)(x)這個函數,讓filter來使用.
光解釋以上觀念也打了一個多小時Orz...希望以後更加活用這個概念.
沒有留言:
張貼留言