Scala Learning(4): Currying柯里化的推演

本文展示加法和乘法的兩個例子,最後使用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)

全文完 :)

發佈了158 篇原創文章 · 獲贊 25 · 訪問量 94萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章