理解函數式編程語言中的組合--前言(一)

理解函數式編程語言中的組合--前言(一)

函數式編程思想能夠用一句話總結,即:可組合的類型+可組合的函數,我在《使用函數式語言作領域建模》一文描述瞭如何使用可組合的類型進行領域建模。這篇文章就是用來講明後半部分,即--理解可組合的函數。我假設讀者已經對「Higher order function」, 「Currying「, 」Immutable「等基本概念有所瞭解,並擁有基礎的TypeScript知識便可。
這一切還得從抽象提及。編程

抽象的重要性

人類可以解決復瑣事物的一個重要方法就是抽象,代碼也同樣。有了抽象,你的代碼纔不會變成流水帳,實際上那些讓人讀起來賞心悅目的好代碼,必定擁有良好的抽象。抽象可讓你避免陷入細節,經過幾個重要的類名或者接口,讓別人快速識別你的設計。
固然,這一切的前提是,閱讀代碼的人也擁有相似的抽象思想,他纔可以心照不宣你的意圖。若是你在讀代碼的時候,本身是怎麼想的,正好代碼就是這樣設計的,你纔會以爲代碼可讀性太強了。
怎麼樣你們才能設計出一致的抽象呢?
《設計模式》就是這樣一本把常見問題總結成一些列模式的書籍。換句話說,《設計模式》提供了常見問題的抽象方式並提供了相關的術語。
固然你的設計好很差,還取決於你是否正確識別到了問題的本質,並恰如其分的實現了某個已知的設計模式。若是閱讀代碼的人擁有跟你相似的抽象知識,他就可以迅速明白你的設計和意圖。設計模式

函數式編程中的抽象

若是說《設計模式》總結了OO思想中的常見抽象方式,那麼函數式編程語言也擁有本身的抽象方式。
看下面的這兩行數學運算:數組

1 + 2 = 3

這行數學運算很是簡單,以致於靠直覺就能判斷他的真確性。這行代碼能夠描述爲:兩個「數字」經過「相加」任然爲「數字」。
若是咱們把"數字「泛化,將"相加」推廣開來,就能夠用在其餘事物身上,例如:編程語言

"a" + "b" = "ab"

對字符串也是適用的,兩個字符串經過一個運算符合併爲一個新的字符串。沒錯,這就是組合的基礎。
函數式編程中的抽象叫作《範疇輪》Category theory,是一門研究如何組合事物的數學科學。其中,「事物」被稱爲object, 但這個object並非OO中的那個對象,而事物之間的轉化或者映射被稱爲morphisms,翻譯爲中文叫射態,對應到編程語言中,就是函數。《範疇論》在函數式編程語言中的地位,能夠類比《設計模式》在OO中的地位。函數式編程

爲何須要《範疇論》

這要從函數的組合開始提及,咱們知道函數式編程語言沒有OO語言中的那些概念,例如類,繼承,依賴注入(有的語言有FP和OO兩種範式, 例如Scala, F#等,請不要糾結)。只靠函數,爲大型的工程化實踐帶來了挑戰。 玩過樂高的同窗都知道,樂高的零件都是擁有獨立功能的小部件,然而,卻有人用它拼出了汽車,飛機甚至是航空母艦,這充分說明了組合的力量。
那麼函數是如何組合的呢?看下面的代碼:函數

const add = (a: number, b: number) => a + b
const sub1 = (a: number) => a - 1

聲明兩個函數add和sub1, 像lodash或fp-ts等庫都會提供一個叫flow的函數,flow的做用就是把若干個函數組合起來:翻譯

const addThenSub1 = flow(add, sub1)

expect(addThenSub1(1, 2)).toBe(2)

此時addThenSub1變成了一個新的函數,最後再將參數做用在上面就能夠獲得結果。flow理論上能夠支持任何數量的函數組合。然而,flow有個致命的問題,他要求上一個函數的返回值類型跟下一個函數的輸入類型一致,例如,上面例子中的add若是返回string, 那麼鏈接就失敗了。另外對sub1的參數數量也有要求,即除了第一個函數add, 後面的函數只能接受一個參數。
其實這兩條限制就爲函數的組合判了死刑,即:
雖然函數是能夠組合的,但並非全部的函數都能任意組合。
《範疇論》就是這樣一門數學科學,他幫你抽象出了事物的轉化或組合模式,你只要按照他總結的模式設計,就能將函數組合起來。設計

相關文章
相關標籤/搜索