天天看點

泛函程式設計(2)-初次體驗泛函程式設計

  泛函程式設計和數學方程式解題相似;用某種方式找出問題的答案。泛函程式設計通用的方式包括了模式比對(pattern matching)以及遞歸思維(recursive thinking)。我們先體驗一下:(在閱讀本系列部落格文章之前,相信讀者已經對scala語言及repl用法有所了解了。在這就不去解釋scala的文法語意了。)

先來個簡單的:

很明顯,這個函數的是一個純函數,也是一個完整函數。因為函數主體涵蓋了所有輸入值(注意: case _ =>)。我們可以預知任何輸入msgid值所産生的結果。還有,函數中沒有使用任何中間變量。看看引用情況:

恰如我們預測的結果。

再來看看一個遞歸(recursion)例子:階乘(factorial)是一個經典樣例:

也可以用模式比對方式:

用模式比對方式使函數意思表達更簡潔、明了。

我們試着用“等量替換”方式逐漸進行約化(reduce)

可以得出預料的答案。

遞歸程式可以用 loop來實作。主要目的是防止堆棧溢出(stack overflow)。不過這并不妨礙我們用遞歸思維去解決問題。 階乘用while loop來寫:

注意factorial_2使用了本地變量k,acc。雖然從表達形式上失去了泛函程式設計的優雅,但除了可以解決堆棧溢出問題外,運作效率也比遞歸方式優化。但這并不意味着完全違背了“不可改變性”(immutability)。因為變量是鎖定在函數内部的。

最後,也可用tail recursion方式編寫階乘。讓編譯器(compiler)把程式優化成改變成 loop 款式:

得出的同樣是正确的答案。這段程式中使用了@annotation.tailrec。如果被标準的函數不符合tail recusion的要求,compiler會提示。