函數語言程式設計的優與劣

2016-07-20    分類:其他、程式設計開發、首頁精華0人評論發表於2016-07-20

本文由碼農網 – 孫騰浩原創翻譯,轉載請看清文末的轉載要求,歡迎參與我們的付費投稿計劃

如今函數語言程式設計越來越流行。越來越多的程式語言支援函式式程式設計風格,人們學習如何使用它們。函數語言程式設計已不像以前那麼小眾——現在Ruby,Java和JavaScript都使用了函數語言程式設計思想。

這些語言都有函式式的特性,但不是函式式語言。我的經驗之談,函式式語言,如Erlang或ML擁有其他主流語言缺少的特性,能讓程式設計更加安全的特性。其中之一便是使用遞迴和引數模式匹配(argument pattern matching)控制迴圈。你也可以將這些設計用於流控制( flow control)。另一個便是認真對待常量賦值。我這裡提到常量賦值因為在這些語言中,一旦你給變數繫結一個值,直到離開作用域前會一直繫結。這個特性帶來的弊端就是學習如何使用它們開發軟體很困難。對於我們這些用強型別語言的開發者,尤其困難。

遞迴和模式匹配

函數語言程式設計語言特性是執行期優化遞迴。使用尾呼叫優化,執行期提供高效的回撥環境,使每個回撥用相同的棧幀(stack frame)。再加上引數模式匹配,你可以像寫歸納法證明(高中數學的歸納法)那樣寫表示式函式。你有一個基礎步驟和歸納步驟。基礎步驟結束遞迴,歸納步驟重複遞迴。通過這種方式,你可以定義函式處理列表或集合。函式的每個變數在每次呼叫中繫結,這使得變數繫結更易於管理。下面是個虛擬碼例子:

looper(_) := return 0
looper(h, t) := return t + looper(h)

這裡,我們定義了一個函式looper()對列表內容求和。

第一個步驟是基礎步驟——如果列表為空,我們返回0。第二個步驟是歸納步驟——如果列表有頭元素和尾元素,然後我們把尾元素通過遞迴呼叫looper()方法求和。如果列表中只剩一個元素,這個元素繫結到變數t,遞迴呼叫匹配基礎步驟(因為變數h為空),然後遞迴展開。

在函式式語言中,尾呼叫優化確保了棧幀重複使用,所以本質上結構和for、while迴圈一樣,比如C語言。

如果你在Ruby或JavaScript中使用它,你必須確保在使用函式迴圈列表前尾遞迴優化是可用的。如果沒有,你將在遞迴中遇到效能問題。你在Ruby或JavaScript中只需要把基礎步驟放在歸納步驟前面就行。

常量賦值

這點在函式式語言中很難實現。畢竟用不可變的值表示可變的狀態非常困難。你又該怎麼辦呢?

記住,變數賦值只在當前作用域有效。所以你如何應對這種情況?你讓作用域很小,只在函式呼叫時繫結必須的變數。你不能編寫修改狀態的程式碼,比如在一系列迴圈中。你只能在函式呼叫時繫結狀態,然後遞迴。通過這種方式,你可以維護狀態改變,在繫結狀態變數值時很難出現錯誤。

不要使用全域性變數。它會跑到作用域外。

相比那些所謂擁有函數語言程式設計的語言,這就是你將在真正函式式語言中看到的兩點關鍵不同點。函式式程式設計讓你的重用能力更上一層樓,使程式碼更清晰,不過在沒有優化的執行環境中會有潛在的效能代價。

譯文連結:http://www.codeceo.com/article/functional-programming.html
英文原文:Functional Programming: The Good and the Bad
翻譯作者:碼農網 – 孫騰浩
轉載必須在正文中標註並保留原文連結、譯文連結和譯者等資訊。]

相關文章