高階函數

在函數式編程中,函數可以像任何其他數據類型一樣被傳遞和操作。把明細動作包在函數中作爲參數傳入。

這篇文章包含如下主要內容:

1.可以創建匿名函數,並把匿名函數交給其他函數。

2.許多集合方法都接受函數參數,將函數應用到集合中的值。

3.可以創建操作代碼塊的函數,它們看上去像是內建的控制語句。


1.作爲值的函數:

可以在變量中存放函數。並且可以對函數做兩件事情:

(1)調用它

(2)傳遞它,存在一個變量中,或者作爲參數傳遞給另一個函數。

下面的例子展示了對函數做的上邊這2種操作:

    /**
     * 1.作爲值的函數,可以對函數做兩件事情:(1)調用它;(2)傳遞它,將函數傳遞給另外一個函數。
     */
    import scala.math._
    val pi = 3.14
    //將函數傳遞給一個變量, 可以寫成:ceil _ 或者 ceil(_)
    val fun = ceil _
    //調用函數
    println(fun(pi))
    //傳遞函數
    val output_array = Array(1.34,9.984,23.4).map { fun }
    println(output_array.mkString(","))


2.匿名函數:

在scala中,不需要爲每一個函數命名,下面是一個匿名函數。 可以將匿名函數傳給變量,或者直接將匿名函數傳給另外一個函數。

    /**
     * 2.匿名函數
     */
    //把匿名函數傳給一個變量
    val noname_func = (x:Double) => 3*x
    //把匿名函數傳給另外一個函數
    val output_array2 = Array(1.34,9.984,23.4).map { (x:Double) => 3*x }
    println(noname_func(2.32))
    println(output_array2.mkString(","))


3.帶函數參數的函數:

實現接受另一個函數作爲參數的函數。如下面定義的函數:

def valueAtOneQuarter( f:(Double) => Double ) = f(0.25)

函數valueAtOneQuarter的參數是任何可以接受Double並返回Double的函數。valueAtOneQuarter的參數類型是 一個帶有單個參數的函數,寫作 (參數類型) => 結果類型 。

valueAtOneQuarter的類型可以寫成是:((Double) => Double) => Double 


由於valueAtOneQuarter是一個接受函數參數的函數,因此被稱爲“高階函數”(higher-order function)。

高階函數可以產生另一個函數。例如下邊例子中的multBy函數:

    /**
     * 3.帶函數參數的函數
     * 寫一個能產出能夠乘以任何數額的函數
     * 
     */
    println("------------------測試:帶函數參數的函數-----------------------")
    //這裏的參數可以是任何接收Double並返回Double的函數。
    def valueAtOneQuarter( f:(Double) => Double ) = f(0.25)
    def multBy(factor:Double) = (x:Double) => x*factor
    val testmul = multBy(4)
    println(testmul(8))

我們可以分析出multBy函數的類型是:

(Double) => ((Double) => Double)


4.參數推斷:

當你把一個匿名函數傳給另一個函數或方法時,Scala會推斷出類型信息。

valueAtOneQuarter( (x:Double) => 3*x )

由於Scala可以推斷出傳給valueAtOneQuarter函數的參數類型是: (Double) => Double ,所以:Double完全可以省略。簡化成:

valueAtOneQuarter( (x) => 3*x )

當匿名函數的參數只有一個時,可以省略括號,那麼可以進一步簡化爲:

valueAtOneQuarter( x => 3*x )

如果參數在=>右側只出現一次,可以用_替換掉它,進一步簡化爲:

valueAtOneQuarter(3*_)


5.一些常用的高階函數:

(1) map函數:將函數應用到集合的每一個元素,並返回結果。

(2) foreach函數:foreach 和 map 很像,只不過它的函數不返回任何值。foreach只是簡單地將函數應用到每一個元素。

(3) filter函數:輸出所有匹配某個特定條件的元素。

(4) reduceLeft函數: 接受一個二元的函數(即:帶有2個參數的函數),並將它應用到序列中的所有元素,從左到右。它和reduce的區別是,reduceLeft順序是固定的(從左到右),但是reduce是沒有順序的(隨機的)。

下面代碼包含以上4個函數:

    /**
     * 4.一些常用的高階函數的使用
     */
    println("------------------測試:一些常用的高階函數的使用-----------------------")
    //將1到9的一個集合每個都乘3
    println(1.to(9).map{ 3*_ })
    //foreach使用
    1.to(9).map("*" * _).foreach{println _}
    //filter只取符合條件的值
    println(1.to(9).filter {_ % 2 == 0 })   // 或者filter{ x => x % 2 == 0 }
   //reduceLeft接收一個二元函數,兩個下劃線分別是2個參數。
    println(1.to(9).reduceLeft(_ + _))


6 .閉包:

對於返回的2個函數:trible 和 half ,它們都有自己各自的設置。trible的factor是3,half的factor是0.5。

那麼對於multBy函數,每一個它返回的函數都有各自的factor設置,這樣的函數叫做閉包。這些函數實際是以類的方式實現的,該類有一個實例變量factor和一個包含了函數體的apply方法。

    /**
     * 5.閉包
     * 
     */
     println("------------------測試:閉包-----------------------")
     val trible = multBy(3)
     val half = multBy(0.5)
     println(trible(18) + " " + half(18))


7.柯里化:

柯里化:指的是將原來接受2個參數的函數變成新的接受一個參數的函數的過程。新的函數返回一個以原有第二個參數作爲參數的函數。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章