天天看點

從 redux 的純函數到函數式程式設計

作者:王少飛

在做業務時我們用 react + redux 架構,其中 redux 的 reducers 是用的純函數。這裡什麼是純函數?為什麼要用純函數?純函數的好處是什麼?接下來的我們一起研究下。

redux 強調 reducers 一定要是純函數

從 redux 的純函數到函數式程式設計

滿足以上兩條的函數成為純函數:

在相同的輸入值時,需産生相同的輸出。函數的輸出和輸入值以外的其他隐藏資訊或狀态無關,也和由I/O裝置産生的外部輸出無關

不能有語義上可觀察的函數副作用,諸如“觸發事件”,使輸出裝置輸出,或更改輸出值以外物件的内容等

從 redux 的純函數到函數式程式設計
從 redux 的純函數到函數式程式設計

圖一中<code>slice</code>函數在相同的輸入時,輸出總是一樣的,并且<code>arr</code>并沒有改變,是以是純函數

從 redux 的純函數到函數式程式設計

圖二中<code>splice</code>函數在輸入相同是,輸出并不相同,并且<code>arr</code>發生了改變,是以是非純函數

如下圖所示,如果我們把reducers的純函數修改為不純的函數:

純函數的代碼

從 redux 的純函數到函數式程式設計

修改為不純的函數,我們在reducer内修改了舊的state變量

從 redux 的純函數到函數式程式設計

下面來看下redux是如何處理的

從 redux 的純函數到函數式程式設計

reducer将舊的狀态(prev)和要修改的資料一起傳進去,然後傳回一個新的(next)狀态,prev和next相比較來确定storge資料是否改變。如果我們用不純的函數,prev和next将一緻,就算資料改變,hasChanged也會是false。

從 redux 的純函數到函數式程式設計

維基百科的解釋不太通俗,我們來看下他具有那些特點:

函數是"第一等公民"

所謂"第一等公民"(first class),指的是函數與其他資料類型一樣,處于平等地位,可以指派給其他變量,也可以作為參數,傳入另一個函數,或者作為别的函數的傳回值。

隻用"表達式",不用"語句"

"表達式"(expression)是一個單純的運算過程,總是有傳回值;"語句"(statement)是執行某種操作,沒有傳回值。函數式程式設計要求,隻使用表達式,不使用語句。也就是說,每一步都是單純的運算,而且都有傳回值。

原因是函數式程式設計的開發動機,一開始就是為了處理運算(computation),不考慮系統的讀寫(I/O)。"語句"屬于對系統的讀寫操作,是以就被排斥在外。

當然,實際應用中,不做I/O是不可能的。是以,程式設計過程中,函數式程式設計隻要求把I/O限制到最小,不要有不必要的讀寫行為,保持計算過程的單純性。

沒有"副作用"

所謂"副作用"(side effect),指的是函數内部與外部互動(最典型的情況,就是修改全局變量的值),産生運算以外的其他結果。

函數式程式設計強調沒有"副作用",意味着函數要保持獨立,所有功能就是傳回一個新的值,沒有其他行為,尤其是不得修改外部變量的值。

不修改狀态

上一點已經提到,函數式程式設計隻是傳回新的值,不修改系統變量。是以,不修改變量,也是它的一個重要特點。

在其他類型的語言中,變量往往用來儲存"狀态"(state)。不修改變量,意味着狀态不能儲存在變量中。函數式程式設計使用參數儲存狀态。

引用透明

引用透明(Referential transparency),指的是函數的運作不依賴于外部變量或"狀态",隻依賴于輸入的參數,任何時候隻要參數相同,引用函數所得到的傳回值總是相同的。

有了前面的第三點和第四點,這點是很顯然的。其他類型的語言,函數的傳回值往往與系統狀态有關,不同的狀态之下,傳回值是不一樣的。這就叫"引用不透明",很不利于觀察和了解程式的行為。

從後面三點可以看出:函數式程式設計要求函數也會是純函數。

傳統的程式設計語言可能是這樣

函數式程式設計是這樣:

看下它有哪些好處:

代碼簡潔,開發快速

函數式程式設計大量使用函數,減少了代碼的重複,是以程式比較短,開發速度較快。

接近自然語言,易于了解

函數式程式設計的自由度很高,可以寫出很接近自然語言的代碼。

更友善的代碼管理

函數式程式設計不依賴、也不會改變外界的狀态,隻要給定輸入參數,傳回的結果必定相同。是以,每一個函數都可以被看做獨立單元,很有利于進行單元測試(unit testing)和除錯(debugging),以及子產品化組合。

易于"并發程式設計"

函數式程式設計不需要考慮"死鎖"(deadlock),因為它不修改變量,是以根本不存在"鎖"線程的問題。不必擔心一個線程的資料,被另一個線程修改,是以可以很放心地把工作分攤到多個線程,部署"并發程式設計"(concurrency)。

函數式程式設計深入了解(待續)

原文連結:http://ivweb.io/topic/58b41ab1aece9f5950397f07