1. 程式人生 > >Scala:Function(高階函數語言程式設計)

Scala:Function(高階函數語言程式設計)

一個可以進行高階函數語言程式設計的模組,我們來看看它都實現了哪些操作,並結合原始碼理解一下。

  • def chain[a](fs: Seq[(a) ⇒ a]): (a) ⇒ a
    把一些列的方法串起來,挨個執行,每個方法的結果,回作為下一個方法的入參
/**定義兩個函式*/
  def fun1 = (v:Int) => {
    val result = v * 10
    println(result)
    result
  }
  def fun2 = (v:Int) => {
    val result = v * 100
    println(result)
    result
  }
  //使用
val funs = Seq(fun1,fun2) Function.chain[Int](funs)(2) /**fun1的結果作為fun2的入參 20 2000 */

看下chain的原始碼

def chain[a](fs: Seq[a => a]): a => a = { x => (x /: fs) ((x, f) => f(x)) }

看到 /: 這個符號是不是有點眼熟,我們在Scala:Array(集合、序列)裡提到過序列的操作中就有這個操作符,他會遍歷序列中的元素去執行指定的操作。

  • def const[T, U](x: T)(y: U): T

    這是一個返回常量的方法,直接返回 x 值,看原始碼
def const[T, U](x: T)(y: U): T = x

假如我們要把一個序列中的元素替換成同一個值,我們可以使用序列的map方法

List(1, 2, 3, 4, 5).map(_=>7)

那這時我們可以用const來處理

List(1, 2, 3, 4, 5).map(Function.const(7))
/**對應原始碼中的x就是7,y就是List中的每個元素
如果我們按照 x+":"+y的形式列印,就是
7:1
7:2
7:3
7:4
7:5
*/
  • def tupled[a1, a2, b](f: (a1, a2) ⇒ b): ((a1, a2)) ⇒ b

    將二元函式轉換為一個一元函式,引數為Tuple2型別
  def tupleFunc = (a:Int,b:Int) => {
    a+b
  }
  /**使用*/
    val funs = Function.tupled(tupleFunc)
    val v = (1,3)
    println(v.getClass.getName)
    println(funs(v))     //  4
  • def tupled[a1, a2, a3, b](f: (a1, a2, a3) ⇒ b): ((a1, a2, a3)) ⇒ b
    道理同 tupled[a1, a2, b]
  • def tupled[a1, a2, a3, a4, b](f: (a1, a2, a3, a4) ⇒ b): ((a1, a2, a3, a4)) ⇒ b
    道理同 tupled[a1, a2, b]
  • def tupled[a1, a2, a3, a4, a5, b](f: (a1, a2, a3, a4, a5) ⇒ b): ((a1, a2, a3, a4, a5)) ⇒ b
    道理同 tupled[a1, a2, b]

  • def untupled[a1, a2, b](f: ((a1, a2)) ⇒ b): (a1, a2) ⇒ b
    作用和tupled[a1, a2, b]相反

  def tupleFunc = (v:Tuple2[Int,Int]) => {
    v._1 + v._2
  }
  //轉換
    val funs = Function.untupled(tupleFunc)
    println(funs(2,6)) /** 8 */
  • def untupled[a1, a2, a3, b](f: ((a1, a2, a3)) ⇒ b): (a1, a2, a3) ⇒ b
    道理同 tupled[a1, a2, b]
  • def untupled[a1, a2, a3, a4, b](f: ((a1, a2, a3, a4)) ⇒ b): (a1, a2, a3, a4) ⇒ b
    道理同 tupled[a1, a2, b]
  • def untupled[a1, a2, a3, a4, a5, b](f: ((a1, a2, a3, a4, a5)) ⇒ b): (a1, a2, a3, a4, a5) ⇒ b
    道理同 tupled[a1, a2, b]

  • def uncurried[a1, a2, b](f: (a1) ⇒ (a2) ⇒ b): (a1, a2) ⇒ b
    把一個柯里化函式轉換為但 2 個引數的函式

/**宣告一個柯里化函式*/
def curriedSum = (x:Int)=>(y:Int) => x + y
//轉換
val funs = Function.uncurried(curriedSum)
println(funs(1,6))      // 7

原始碼
方法返回結果是帶(a1, a2)兩個引數的函式

def uncurried[a1, a2, b](f: a1 => a2 => b): (a1, a2) => b = {
    (x1, x2) => f(x1)(x2)
}
  • def uncurried[a1, a2, a3, b](f: (a1) ⇒ (a2) ⇒ (a3) ⇒ b): (a1, a2, a3) ⇒ b
    道理同 uncurried[a1, a2, b]
  • def uncurried[a1, a2, a3, a4, b](f: (a1) ⇒ (a2) ⇒ (a3) ⇒ (a4) ⇒ b): (a1, a2, a3, a4) ⇒ b
    道理同 uncurried[a1, a2, b]
  • def uncurried[a1, a2, a3, a4, a5, b](f: (a1) ⇒ (a2) ⇒ (a3) ⇒ (a4) ⇒ (a5) ⇒ b): (a1, a2, a3, a4, a5) ⇒ b
    道理同 uncurried[a1, a2, b]

  • def unlift[T, R](f: (T) ⇒ Option[R]): PartialFunction[T, R]
    將 A => Option[B] 型別的函式轉換為 PartialFunction[T, R] 型別函式

  def optionFun(x : Int) = {
    println(x)
    if (x > 0) Some(x*10) else None
  }
  //使用
    val funs = Function.unlift(optionFun)
    val chars = Array(1,2,3)
    //collect需要PartialFunction型別引數
    val newchars = chars.collect(funs)
    println(newchars.mkString(","))
  /**輸出為 10,20,30 */

原始碼(內部呼叫的是PartialFunction.unlifted方法)

def unlift[T, R](f: T => Option[R]): PartialFunction[T, R] = PartialFunction.unlifted(f)