主要來自 Scala 語言發明人 Martin Odersky 教授的 Coursera 課程 《Functional Programming Principles in Scala》。python
把其餘函數做爲參數或者做爲返回值,就是 higher order functions,python 裏面也能夠看到這樣使用的情形。在酷殼上的博客有一個例子就是將函數做爲返回值。c++
在 python 裏邊叫 lambda 函數,經常與 map(), filter(), reduce() 聯合使用,前面也寫過一篇這樣的博客。less
舉一個 scala 的 reduce 的例子,f: Int => Int
表示 f 是一個整數映射到整數的函數,計算下面公式:ide
def sum(f: Int => Int, a: Int, b: Int): Int = { def loop(a: Int, acc: Int): Int = if (a > b) acc else loop(a + 1, f(a) + acc) loop(a, 0) } def sumInts(a: Int, b: Int) = sum(x => x, a, b) // f(n)=n def sumCubes(a: Int, b: Int) = sum(x => x * x * x, a, b) // f(n)=n*n*n println(sumInts(2, 7)) //求和 println(sumCubes(3, 10)) //求立方和
把一個函數的多個參數分解成多個函數, 而後把函數多層封裝起來,每層函數都返回一個函數去接收下一個參數這樣,能夠簡化函數的多個參數。函數
// sum 返回函數 sumF,風格與 python 類似 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 } def sumInts = sum(x => x) def sumCubes = sum(x => x * x * x) sumInts(1, 5) //> res0: Int = 15 sumCubes(1, 5) //> res1: Int = 225 sum(x=>x)(1, 5) //> res2: Int = 15 (sum(x=>x))(1, 5) //> res3: Int = 15
更爲簡短的寫法:oop
def sum(f: Int => Int)(a: Int, b: Int): Int = if (a > b) 0 else f(a) + sum(f)(a + 1, b) sum(x => x)(1, 5) // 第一個()至關於建立了一個匿名函數
mapReduce 實現過程包括 map 一一映射函數和 reduce 函數及單位元素 zero(乘爲1,加爲0),參數包括序列區間 [a, b] 兩個參數,假設咱們求 [a, b] 區間上全部元素的平方和:ui
def mapReduce(map: Int => Int, reduce: (Int, Int) => Int, zero: Int)(a: Int, b: Int): Int = if (a > b) zero else reduce(map(a), mapReduce(map, reduce, zero)(a + 1, b)) def sumOfSquare(a: Int, b: Int) = mapReduce(x => x*x, (x, y) => x + y, 0)(a, b) //這裏肯定了三個,留下參數a,b
好比求立方和,四次方和等,更靈活的用法是 map 和 reduce 能夠先指定一個reduce(都是sum),使用時再指定另外一個(map),代碼就不貼了。總之,全部mapreduce設置,包括map,reduce, zero, a, b均可以無序設置,替換組合成包含不一樣參數列表的新函數。this
構造一個分數(rational)類,實現加減、比大小等基本功能。spa
object rationals { val x = new Rational(1, 3) //> x : week3.Rational = 1/3 val y = new Rational(5, 7) //> y : week3.Rational = 5/7 val z = new Rational(3) //> z : week3.Rational = 3/1 x.numer //> res0: Int = 1 x.sub(y).sub(z) //> res1: week3.Rational = 71/-21 y.add(y) //> res2: week3.Rational = 10/7 x.less(y) //> res3: Boolean = true x.max(y) //> res4: week3.Rational = 5/7 } class Rational(x: Int, y: Int) { require(y != 0, "denomitor must be nonzero") // scala 的構造函數就是執行body def this(x: Int) = this(x, 1) // 第二種構造函數, 補全到第一種 private def gcd(a: Int, b: Int): Int = if (b==0) a else gcd(b, a % b) //private函數,求最大公約數 val numer = x / gcd(x, y) // 每次構造新類,都化簡 val denom = y / gcd(x, y) // val,gcd函數只計算一次 def add(that: Rational) = new Rational( numer * that.denom + denom * that.numer, // 交叉相乘相加 denom * that.denom) def neg: Rational = new Rational(-numer, denom) def sub(that: Rational) = add(that.neg) def less(that: Rational) = numer * that.denom < that.numer * denom def max(that: Rational) = if (this.less(that)) that else this // this 關鍵字,表示使用該method的object override def toString = numer + "/" + denom // 每次打印類的格式 }
c++裏面有操做符的重載,在scala裏面技術層面上來講沒有操做符這個概念。好比 1 + 2
實際是 1.+(2)
。 + 是對象 1 的一種方法。Scala 實現 1 + 2
這種寫法須要兩種技術,以上面的例子來分析:scala
r.add(s)
能夠寫成 r add s
,任何只包含一個參數的方法均可以寫成這樣的形式,這種作法叫Infix Notation。a + b
,分數的加法若是是 a add b
,風格不一致。還有一個方法叫 Relaxed Identifiers。大概意思是標誌符不只能夠是字母開頭的字符串組成,還能夠是運算符(若是後面是冒號,加至少一個空格,不然會將冒號也看出標誌的一部分)。實現與整數加法風格一致的分數運算,代碼以下:
package week3 object rationals { val x = new Rational(1, 3) //> x : week3.Rational = 1/3 val y = new Rational(5, 7) //> y : week3.Rational = 5/7 val z = new Rational(3) //> z : week3.Rational = 3/1 -x //> res0: week3.Rational = 1/-3 x - y - z //> res1: week3.Rational = 71/-21 y + y //> res2: week3.Rational = 10/7 x < y //> res3: Boolean = true x * x + z * z //> res4: week3.Rational = 82/9 } class Rational(x: Int, y: Int) { require(y != 0, "denomitor must be nonzero") def this(x: Int) = this(x, 1) private def gcd(a: Int, b: Int): Int = if (b==0) a else gcd(b, a % b) val numer = x / gcd(x, y) val denom = y / gcd(x, y) def + (that: Rational) = new Rational( numer * that.denom + denom * that.numer, denom * that.denom) def unary_- : Rational = new Rational(-numer, denom) // unary_:一元運算符和二元運算符不一樣,一元要特意指出 def - (that: Rational) = this + -that def < (that: Rational) = numer * that.denom < that.numer * denom def * (that: Rational) = new Rational(numer * that.numer, denom * that.denom) override def toString = numer + "/" + denom // 打印類的格式 }
注意到上面代碼中 x*x + z*z
沒用括號也能計算出準確的結果,這是由於 scala 通用一套根據標識符肯定運算優先級的規則表。