#導覽列 #文章列表 #許洛豪
在光之翼的守護下訴說著一段段的英雄傳說。 [ 首頁 | 網誌 | 相簿 | 留言 | 訂閱 ]

遞回只應天上有,凡人應當用迴圈。

距離脫離尼特族接近兩個星期了,工作方面還在努力學習中,大部份的時間都在追別人寫的東西,只有小修小改而已,希望自己也能加快腳步,盡量能夠早點弄熟自己要接手的東西吶。

回到正題,『遞迴只應天上有、凡人應當用迴圈』這句話應該不少人聽過了,我在很久很久以前也寫過一篇『Haskell 真的比較好懂和不容易出錯嗎?』的文章。

不過,事後證明,我錯了。我接觸了 Scala 之後,我認為這句話很有可能是錯的,遞迴加上 Pattern Matching 或許在某些時候真的比較好懂。

直接來看例子吧,這個例子很簡單:給一個 List,請找出最後一個元素。

程式碼如下:

def last[T] (list: List[T]): T = list match {
    case x :: Nil    => x                 // 如果這個值後面沒有東西,他就是目標
    case x :: remain => last(remain)      // 不然的話繼續處理剩下來的東西
    case _ => throw new Exception("opps") // 不可能有這兩種以外的狀況
}

整個程式碼就和用說的一樣簡單容易理解,而另一個遞迴比較好懂的經典例子應該就是費伯納西數列了吧。

def fib (n: Int): Int = {
    n match {
        case 0 => 0                     // 如果是 fib(0) 就是 0
        case 1 => 1                     // 如果是 fib(1) 就是 1
        case x => fib (x-1) + fib (x-2) // 不然的話就是前兩項相加
    }
}

幾乎和用嘴巴上數學定義一模一樣。XD

但話說回來,我還是覺得 Haskell 很難懂,理由很簡單--他只給你一種他認為『對』的方法來做事,但他的『對』不見得在每種情況下都是直覺的。

例如在我之前的那一篇文章裡提到的,『把 List 裡數字加總』這件事,如果是在 Scala 裡,可以分別寫出兩種版本:

def sumByIterate (list: List[Int]): Int = {

    // 一開始計算機上是 0
    var sum: Int = 0

    // 一個個把 List 裡的元素加到計算機上
    for (x <- list) { sum = sum + x }

    // 其實上面那一句你也可以這樣寫
    // list.foreach {x => sum = sum + x}

    // 最後就是結果
    return sum
}
def sumByRecursive (list: List[Int]): Int = {
    list match {
        case Nil     => 0
        case x :: xs => x + sumByRecursive(xs)
    }
}

我還是覺得 sumByIterate 比較好懂和直覺,三行解決,不用遞回,做的動作就和我們要利用計算機把一個數列給加總一模一樣。

我相信當你要拿計算機加總一個數列的時候,是不會去想『第一個數字再加上其剩下的數字的總合就是答案』這種事,或者去做『從數列最後一個開始往回加』的動作的。

畢竟,加總不就是一個一個把他給打到計算機裡嗎--正是我們第一個版本做的事情。

所以我還是喜歡 Scala 這類 Multi-Paradigm 的程式語言--給你一個完整的工具箱,裡面有各種扳手和鉗子,讓你決定哪一種比較合適,而不是只給一個平口老虎鉗,叫你什麼事都要用這隻老虎鉗來做……

將本文加入 Hemidemi 書籤
Brian Hsu (墳墓)
2010-02-06 (週六) 22:25:43

第 1 篇迴響

def sumByFold (list: List[Int]): Int = (0 /: list)(_ + _)

一行 :QQ

由 Plummtw 在 2010/02/16 發表

第 2 篇迴響

我強列譴責這是作弊。XD

真要說起來,我自己不認為那會比較容易『解釋』給別人聽啦,光一個 recursive 就可以搞死人,更何況這種 recursive 和 high order function 一起來耶。XDDDDDD

但話說回來,現在我大部份是用 list.reduceLeft (+) 或我覺得看起來比較清楚在幹什麼。:p

墳墓 (BrianHsu) 在 2010/02/16 發表

第 3 篇迴響

reduceLeft 後面接的 + 我這版 Scala 它不接受,我沒換最新版的就是了,在等 2.8。

scala> List(1,2,3).reduceLeft( + ) :1: error: illegal start of simple expression List(1,2,3).reduceLeft( + )

由 Plummtw 在 2010/02/17 發表

第 4 篇迴響

Oops,好像是不小心被 Markdown 格式化了。

正確的應該是這樣: list.reduceLeft (_ + _)

基本上行為和 /: 還有 foldLeft 是一樣的,只是預設的起始值是零而已,可以偷懶少打一個參數。XD

墳墓 (BrianHsu) 在 2010/02/17 發表

第 5 篇迴響

對了我想請問一下,一般程式碼在網頁上都怎咩格式化加色彩的?

由 Plummtw 在 2010/02/17 發表

第 6 篇迴響

程式碼格式化的話,主要有兩個,一個是跑在 Server 端的 [GeSHi][http://qbnz.com/highlighter/],用的是 PHP。

另一個是跑在 Client 端的 [SyntaxHighlighter][http://alexgorbatchev.com/wiki/SyntaxHighlighter],就是我現在用的這個,只要 Client 端有 JavaScript 就可以用。

墳墓 (BrianHsu) 在 2010/02/17 發表


留下迴響







請勿使用注音文或火星文!並請遵守發規則,本站亦不歡迎匿名留言。