純函數式編程
在計算機科學中,純函數式編程通常指示一種編程范型,這是建造計算機程序的結構和元素的一種風格,就是將所有計算都當作數學函數的求值(evaluation)。純函數式編程還可以定義為禁用狀態變更和可變數據。
純函數式編程主要在於確保函數遵守函數式范型,只依賴於它們的實際參數,而不用管任何全局或局部的狀態。
純與非純的區別
在純與非純函數式編程之間的確切區別是有爭議的事情[1]。
當一個程序使用了某些函數式編程概念的時候, 比如頭等函數和高階函數,它通常就被稱為是函數式的[2]。但是,頭等函數不必然是純函數式的,由於它可以使用來自指令式范型的技術,比如數組或輸入/輸出方法,故而它們不是純函數程序。事實上,最早被引證為函數式的編程語言,IPL和LISP[3][4],按照當前定義都是非純函數式語言。
純函數式數據結構必然是持久性數據結構。持久性是函數式編程所要求的,如果沒有它,相同的計算就可能返回不同的結果。函數式編程可以使用非純函數式的持久性數據結構,比如持久性數組,而這些數據結構不可以用在純函數式程序中。
純粹採用函數式編程的基礎部件(如map、reduce、filter等),進行響應式編程(異步數據流程編程)的編程范型,被稱為函數式響應式編程。
純函數式編程的性質
單賦值
任何改變現存值的賦值(比如x := x + 1
),在純函數式編程中都是不允許的[5]。在現今的函數式編程中,賦值是被勸阻的,用以支持也叫做「初始化」的單賦值。單賦值是名字綁定的用例,不同於本文其他部分描述的賦值之處在於,它只能做一次,通常是在變量被創建的時候,不允許後續的重新賦值。純函數式編程共通於數據流程編程的這個特徵,簡化了並行計算[6],因為求值的兩個部份如果都是純函數式的就會永不交互。
參照透明性
如果將一個表達式替代為它的值只在程序執行的特定點上是有效的,則這個表達式不是參照透明性的。這些順序點的定義和次序是指令式編程的理論基礎。參照透明性的表達式可以在任何時間求值,既不需要定義順序點也根本不需要對求值次序的任何保證,不需要做這些考慮的編程叫做純函數式編程。
寫參照透明性風格的代碼的好處是能得到智能編譯器,易於靜態代碼分析,和自動進行更好的代碼優化。強制參照透明性的語言的主要缺點是,使得表達天然適合指令式編程的步驟序列的運算,更加蠢笨和更不簡潔。這些語言通常結合某種機制,使得這些任務更加容易而又保持語言的純函數式性質,比如明確子句文法和單子。
參照透明性要求表達式是純函數的,也就是表達式的值對於相同的輸入也必須是相同的,它的求值不能有副作用。在現今的函數式編程中,很少使用副作用。缺少副作用導致程序易於形式驗證。函數式語言比如Standard ML、Scheme和Scala不限制副作用,但是編程者會習慣性的避免使用它們[7]。函數式語言Haskell使用單子行動來表達副作用,比如輸入/輸出和其他有狀態的計算[8][9]。
數據結構
純函數式數據結構,是可以用純函數式語言如Haskell實現的數據結構。實際上,這意味着建造這種數據結構,必須只使用持久性數據類型比如元組、和類型、積類型,和基本類型如整數、字符、字符串。純函數式數據類型,同它們的指令式對應者相比,經常以不同的方式表現[10]。例如,具有以恆定時間來訪問和更新的數組,是多數指令式語言的基本構件,而且很多指令式數據結構,比如散列表和二叉堆,也是基於數組的。數組可以被替代為映射或隨機訪問列表,它容許純函數式實現,但是訪問和更新時間複雜度是對數。因此,純函數式數據結構可以用在非純函數式語言中,但是它們可能不是能得到的最有效率的工具,特別是不要求持久性的情況下。
一般而言,把一個指令式程序轉換成純函數式程序,還需要確保原先可變的那些數據結構,變為顯式的傳遞給並返回自更新它們的函數,這是叫做存儲傳遞風格的一種程序結構。
求值策略
每種求值策略對當純函數式編程時都返回相同的結果。特別是,它確保編程者不需要考慮程序是按什麼次序求值的,因為及早求值(嚴格求值)將返回同惰性求值(非嚴格求值)相同的結果。但是,仍有可能一個及早求值可以不終止,而相同程序的惰性求值會停機。純函數式的好處是惰性求值是可以被更容易的實現,因為所有表達式在任何時刻都返回同樣的結果,不用管程序的狀態,它們的求值可以隨着需要而推延。
純函數式語言
純函數式語言是只認可純函數編程的語言。但是純函數式程序可以用非純函數式的語言寫成。純函數式語言主要有:
歷史上曾有重要影響的還有NPL、Hope、SASL、KRC和Miranda以及Joy等。
參見
引用
- ^ Sabry, Amr. What is Purely Functional Language ?. Journal of Functional Programming. January 1993, 8 (1): 1–22. doi:10.1017/S0956796897002943.
- ^ Atencio, Luis. Functional Programming in Javascript. Manning Publications. 18 June 2016. ISBN 978-1617292828.
- ^ The memoir of Herbert A. Simon (1991), Models of My Life pp.189-190 ISBN 0-465-04640-1 claims that he, Al Newell, and Cliff Shaw are "commonly adjudged to be the parents of [the] artificial intelligence [field]", for writing Logic Theorist, a program which proved theorems from Principia Mathematica automatically. In order to accomplish this, they had to invent a language and a paradigm which, which viewed retrospectively, embeds functional programming.
- ^ McCarthy, John. History of Lisp. In ACM SIGPLAN History of Programming Languages Conference. June 1978: 217–223 [2020-04-24]. doi:10.1145/800025.808387. (原始內容存檔於2008-06-07).
- ^ Crossing borders: Explore functional programming with Haskell 網際網路檔案館的存檔,存檔日期November 19, 2010,., by Bruce Tate
- ^ Marlow, Simon. Parallel and Concurrent Programming in Haskell: Techniques for Multicore and Multithreaded Programming. O'Reilly Media. 18 June 2013. ISBN 978-1449335946.
- ^ Matthias Felleisen et al., How To Design Programs, MIT Press. [2021-02-07]. (原始內容存檔於2021-05-02).
- ^ Haskell 98 report, http://www.haskell.org (頁面存檔備份,存於網際網路檔案館).
- ^ Imperative Functional Programming, Simon Peyton Jones and Phil Wadler, Conference Record of the 20th Annual ACM Symposium on Principles of Programming Languages, pages 71–84, 1993
- ^ Purely functional data structures (頁面存檔備份,存於網際網路檔案館) by Chris Okasaki, Cambridge University Press, 1998, ISBN 0-521-66350-4