Scala柯里化函數和遞歸函數

目錄

一、柯里化函數定義

二、柯里化函數的實現

三、遞歸函數

四、尾遞歸函數

五、綜合性栗子:求​


一、柯里化函數定義

柯里化函數(Curried Functoin)把具有多個參數的函數轉換爲一條函數鏈,每個節點上是單一參數。

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

eg:以下兩個add函數定義是等價的

def add(x:Int,y:Int) = x + y


def add(x:Int)(y:Int) = x + y  //Scala柯里化的語法

二、柯里化函數的實現

函數裏2傳給了a,3傳給了b。函數curriedAdd=2 +3

在addOne中1傳給了a,_傳給了b,之後調用CurriedAdd時4傳給了_,此時採用Call By Value的方式,xian運算_ = 4,此時函數curriedAdd(1)(4)= 1 + 4。

第二種一般用於對某種函數進行統一計算

這是複用了通用型函數的定義,爲了縮小適用範圍,創建一個針對性更強的函數。

優點:可複用性,延遲計算

 

三、遞歸函數

遞歸函數(Recursive Function)在函數式編程中實現循環的一種技術。

eg:計算n!

def factorial (n: Int) :Int = 

  if (n <= 0) 1

  else n * factorial(n - 1)

 弊區:在現代計算機中,我們大都使用堆棧來進行函數的調用,那遞歸的層數一深棧就越多,就容易導致堆棧溢出,這也是爲什麼其他編程不太推薦使用遞歸函數編程的原因。

爲了解決以上弊區的問題的方案,我們叫做尾遞歸函數。

 

四、尾遞歸函數

尾遞歸函數(Tail Recursive Function)中所有遞歸形式的調用都出現在函數的末尾。

當編譯器檢測到一個函數調用時尾遞歸的時候,它就覆蓋當前的活動記錄而不是在棧中去創建一個新的。

 

在函數上寫明“ @annotation.tailrec”表示函數將進行尾遞歸的優化。如果不寫這句,Scala編譯器時不會主動進行尾遞歸優化的。

object tailrec extendsApp{
@annotation.tailrec
  def factorial(n:Int,m:Int):Int=
if(n<=0) m
else factorial(n-1,m*n)
  println(factorial(5,1))
}

 

 

五、綜合性栗子:求

 

object work_hetong {
  def WeWant(f: Int => Int)(a: Int)(b: Int): Int = {
    @annotation.tailrec
    def loop(n: Int, sum: Int): Int = {
      if (n > b) {
        println(s"n = ${n}, sum = ${sum}")
        sum
      } else {
        println(s"n = ${n}, sum = ${sum}")
        loop(n + 1, sum + f(n))
      }
    }
    loop(a, 0)
  }                                               //> WeWant: (f: Int => Int)(a: Int)(b: Int)Int

  def WeWantResult = WeWant(x => x)_              //> WeWantResult: => Int => (Int => Int)
  WeWantResult(1)(5)                              //> n = 1, sum = 0
                                                  //| n = 2, sum = 1
                                                  //| n = 3, sum = 3
                                                  //| n = 4, sum = 6
                                                  //| n = 5, sum = 10
                                                  //| n = 6, sum = 15
                                                  //| res0: Int = 15
}

另一種從大到小的寫寫法,注意參數的改變。

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