定義一個function
在Scala中,定義一個function/value是以以下的語法:def power(x: Double, y: Double): Double = ...
上面的語義是說,我們定義 power(x: Double, y: Double) 為一個Double value,如果以數學函式的觀點就是把(x,y) map到一個Double value,Double也就是此function的return type。
常數也是一個function,數學中有常數函式 (不論input是什麼,永遠output同一個數),所以我們說value和function其實是同一個意義。
function 解析順序
了解一個function在runtime怎麼解析對寫FP來說很重要,如果弄不清楚的話會搞得相當頭大,也很難寫的精簡。看以下範例:和imperative function解析是一樣,先把sumOfSquares的兩個參數替換(substitute)成兩個values,然後分別代入下一個函數式square得到值,之後再往下帶入加減乘除這類的function,一步步替換,直到不能在替換為止。
以上的邏輯稱作substitution model,這是我們在計算一個代數式會用的邏輯。
不過substitution model只能用在沒有"side effect"的函數,什麼意思呢?
以Java的"++" operator來說,以下的expression並不能用substitution model重寫出來:
x++;
x++ 近似於定義 def y(x:Int) : Int = x+1,但是你無法透過任何substitution過程來把x的值換成x+1,除非Scala允許mutable data type。
按照substitution model的邏輯,以下的定義是一個無窮迴圈:
def loop:Int = loop
(1) 把左邊的loop sybmbol換成右邊的定義,也就是loop
(2) 把(1)的結果 loop替換成 其定義,又是loop
...
..
.
call by value / call by name
substitution model的過程是把所有parameter替換成value之後才能代入下一個function,所以就是我們熟悉的call by value的邏輯。那call by name是用什麼解析邏輯呢?如果傳入的參數不先替換成value,而是原封不動地直接帶入function,這樣的邏輯就會產生call by name的結果。
從上面的解析步驟,我們可以看到 2+2 這個expression不會被evaluate,直到再也沒有非primitive function可以代入時,才會被evaluate。
- call by value只會對同一個expression evaluate一次,例如2+2這個expression。
- call by name只在真正用到(reference到,所以名之)這個expression的時候才去evaluate,但是有可能evaluate超過一次,例如2+2這個expression在square function中被evaluate了兩次。
Scala default使用call by value來解析參數,因為可以免除掉無謂的計算,速度差異可能達到exponential等級,但是也提供了用call by name解析參數的語法,例如以下的參數y將會
用call by name解析:
def f(x:Int, y => Int): Int
一個範例算算看
def test(x:Int, y:Int): Int = x * x
(1)
****call by value
test(2, 3)
= 2 * 2
= 4
***call by name
test(2,3)
= 2 * 2
= 4
(2)
****call by value
test(3+4, 3)
= test(7, 3)
= 7 * 7
= 49
***call by name
test(3+4, 3)
= (3+4) * (3+4)
= 7 * (3+4)
= 7 * 7
= 49
(3)
****call by value
test(7, 2*4)
= test(7, 8)
= 7 * 7
= 49
***call by name
test(7, 2*4)
= 7 * 7
= 49
(4)
****call by value
test(3+4, 2*4)
= test(7, 2*4)
= test(7, 8)
= 7 * 7
= 49
***call by name
test(3+4, 2*4)
= (3+4) * (3+4)
= 7 * (3+4)
= 7 * 7
= 49
沒有留言:
張貼留言