本文展示加法和乘法的兩個例子,最後使用MapReduce的思想把兩者統一成一個帶Currying的表達形式。
從high-order functions推演到Currying
原始方法
def sum(f: Int => Int, a: Int, b: Int): Int =
if (a > b) 0
else f(a) + sum(f, a + 1, b)
表示從a到b,把每個int做一次f處理,把所有結果累加起來。
對應”加法”、”立方”、”階乘”,實現三個funtion
def id(x: Int): Int = x
def cube(x: Int): Int = x * x * x
def fact(x: Int): Int = if (x == 0) 1 else fact(x - 1)
把這三個方法填充到原始的sum方法裏,得到三個新方法
def sumInts(a: Int, b: Int) = sum(id, a, b)
def sumCubes(a: Int, b: Int) = sum(cube, a, b)
def sumFactorials(a: Int, b: Int) = sum(fact, a, b)
將前兩個簡化,把function匿名地傳入sum裏,得到
def sumInts(a: Int, b: Int) = sum(x => x, a, b)
def sumCubes(a: Int, b: Int) = sum(x => x * x * x, a, b)
寫起來更簡短一些。
進一步的,我們注意到a: Int,b: Int這倆參數在各個實現裏都是從左到右帶過去的,可以簡化地重新實現原始的sum方法
def sum(f: Int => Int): (Int, Int) => Int = {
def sumF(a: Int, b: Int): Int =
if (a > b) 0
else f(a) + sumF(a + 1, b)
sumF
}
如此,新的sum方法傳入一個f,返回值也是一個function,藉助新的sum,上面三個方法可以這樣實現
def sumInts = sum(x => x)
def sumCubes = sum(x => x * x * x)
def sumFactorials = sum(fact)
使用如
sumCubes(1, 10) + sumFactorials(10, 20)
本質上就是Currying的形式了,展開是:
def sum(f: Int => Int)(a: Int, b: Int): Int = ...
類型是什麼呢?
類型是
(Int => Int) => (Int, Int) => Int
右側也就是Int,即
Int => Int => Int
即
Int => (Int => Int)
MapReduce例子
回到加法的例子:
MapReduce例子
回到加法的例子,用Currying的方式改寫爲:
def sum(f: Int => Int)(a: Int, b: Int): Int =
if (a > b) 0
else f(a) + sum(f)(a + 1, b)
用Currying類似寫一個乘法:
def product(f: Int => Int)(a: Int, b: Int): Int =
if (a > b) 1
else f(a) * product(f)(a + 1, b)
注意到,兩者在初始值、else分支的計算處理上有所不同,使用MapReduce的思想把兩個計算統一起來:
def mapReduce(f: Int => Int, combine: (Int, Int) => Int, initValue: Int)(a: Int, b: Int) : Int =
if (a > b) initValue
else combine(f(a), mapReduce(f, combine, initValue)(a+1, b))
把product套進去,可以表示爲
def product(f: Int => Int)(a: Int, b: Int): Int =
mapReduce(f, (x, y) => x*y, 1)(a, b)
把sum套進去,可以表示爲
def sum(f: Int => Int)(a: Int, b: Int): Int =
mapReduce(f, (x, y) => x+y, 0)(a, b)
全文完 :)