轉自 http://zh.wikipedia.org/zh-tw/%E5%87%BD%E6%95%B0%E5%89%AF%E4%BD%9C%E7%94%A8
在電腦科學中,函式副作用指當呼叫函式時,除了返回函式值之外,還對主呼叫函式產生附加的影響。例如修改全域性變數(函式外的變數)或修改引數。
函式副作用會給程式設計帶來不必要的麻煩,給程式帶來十分難以查詢的錯誤,並且降低程式的可讀性。嚴格的函式式語言要求函式必須無副作用。
下面是函式的副作用相關的幾個概念, 純函式(Pure Function)、非純函式(Impure Function)、引用透明(Referential Transparent)。
純函式
純函式(Pure Function)是這樣一種函式——輸入輸出資料流全是顯式(Explicit)的。
顯式(Explicit)的意思是,函式與外界交換資料只有一個唯一渠道——引數和返回值;函式從函式外部接受的所有輸入資訊都通過引數傳遞到該函式內部;函式輸出到函式外部的所有資訊都通過返回值傳遞到該函式外部。
非純函式
如果一個函式通過隱式(Implicit)方式,從外界獲取資料,或者向外部輸出資料,那麼,該函式就不是純函式,叫作非純函式(Impure Function)。
隱式(Implicit) 的意思是,函式通過引數和返回值以外的渠道,和外界進行資料交換。比如,讀取全域性變數,修改全域性變數,都叫作以隱式的方式和外界進行資料交換;比如,利用 I/O API(輸入輸出系統函式庫)讀取配置檔案,或者輸出到檔案,列印到螢幕,都叫做隱式的方式和外界進行資料交換。
引用透明
引用透明(Referential Transparent)的概念與函式的副作用相關,且受其影響。 如果程式中兩個相同值得表示式能在該程式的任何地方互相替換,而不影響程式的動作,那麼該程式就具有引用透明性。它的優點是比非引用透明的語言的語義更容 易理解,不那麼晦澀。純函式式語言沒有變數,所以它們都具有引用透明性。
範例(Java)
f(x) { return x + 1 }
f(x)函式就是純函式。
a = 0 q(x) { b = a }
q(x) 訪問了函式外部的變數。q(x)是非純函式。
p(x){ print “hello” }
p(x)通過I/O API輸出了一個字元串。p(x)是非純函式。
c(x) { data = readConfig() // 讀取配置檔案 }
c(x)通過I/O API讀取了配置檔案。c(x)是非純函式。
純函式內部有隱式(Implicit)的資料流,這種情況叫做副作用(Side Effect)。我們可以把副作用想像為潛規則。上述的I/O,外部變數等,都可以歸為副作用。因此,純函式的定義也可以寫為,沒有副作用的函式,叫做純函式。
I/O API可以看作是一種特殊的全域性變數。檔案、螢幕、資料庫等輸入輸出結構可以看作是獨立於執行環境之外的系統外全域性變數,而不是應用程式自己定義的全域性變數。
特殊的函式副作用
上述只討論了一般的情況,還有一種特殊的情況,我們沒有討論。有些函式的引數是一種In/Out作用的引數,即函式可能改變引數裡面的內容,把一些資訊通過輸入引數,夾帶到外界。這種情況,嚴格來說,也是副作用。也是非純函式。 比如下面的函式。
process(context) { a = context.getInfo() result = calculate( a ) context.setResult( result ) }
純函式的優點
純函式的好處主要有幾點: