所以函數式編程是什麼(二)

閱讀時間約 5 分鐘

前一篇文章中所提的函數式的三個機制明確說明了它關注的規則與能力具體是什麼。然而這套對於函數式編程的定義主要基於特定的類型系統,作為一個編程範式來說過於狹隘(物件導向的定義也是這樣)。更廣義的,我認為函數式編程主要依循三個原則,它們可以應用於任何程式語言,就算沒有靜態類型系統的支援也可以。例如在不管類型的情況下,有些人認為函數式編程就是盡量減少修改和副作用,它就是其中一個原則的實現。這三個原則分別是:最小能力原則、參考透明原則、單一情境原則,它們從方法論上形塑了函數式編程的風格。


最小能力原則(least power principle)認為定義資料結構、函式、介面、變數等實體時,應該盡量縮減它們的能力。能力越強責任越大,因此過強的能力會讓我們需要考慮的東西變多。能力越弱,就必須藉由實體間的合作完成任務,因此如果能落實這個原則,能力越小反而可以提升這些實體的用處。能力越小也有助於分化職責,並提升程式碼的重用性。更重要的是,透過思考如何縮減能力,我們可以更容易將有意義的耦合與非必要的耦合分離出來,從而得到具有同調性的模型。這個原則在函數式編程的應用範圍非常廣泛,小至一段程式碼,大到整個程式語言的設計,都能看到最小能力原則的影子。很多編程建議都可以歸結於這個原則,例如:宣告變數時應該優先考慮宣告成不可變的、應盡量縮減變數的作用域、函式應該只做一件事並做到最好、iterator/pipeline pattern、介面應該盡量細分。函數式編程與物件導向機制上的差別也能體現這個原則,例如子類關係、實體類型的檢查、類別=資料+介面、介面的繼承等,都是物件導向中相對於函數式編程強大的機制,但這反而讓程式語言在某些層面上更糟了,例如:難以描述具體類型、泛型失去同調性、出現反直覺的多型實作。最小能力原則著重於能力而非模型本身,因此我們常需要解構模型背後的邏輯,而非直接依循模型本身設計程式,這點與物件導向非常不一樣。


參考透明原則(referential transparency principle)認為程式應該盡量參考透明。參考透明性指的是表達式的可取代性:如果一個變數可以像巨集一樣直接取代成它的定義,而程式行為不會因此改變,那麼我們說它是參考透明的。這說明操作的順序、執行次數不應影響結果。反之會互相影響的操作就是不透明的,影響越大則越不透明。變數的修改就是不透明的操作,改變它的順序會影響程式的行為,所以應該盡量減少使用變數修改。更廣義的,如果一個操作可以很容易看出他造成什麼影響,那麼它也應視作參考透明的。例如Java的例外處理必須明確標示於定義上,因此這部分在某種程度上也算是蠻透明的,但是呼叫此函式時無法從語法上判斷是否可能有例外丟出。操作之間的影響應該只由依賴關係決定,如果一個操作使用了前一個操作的結果,那麼它們就有依賴關係,因此它會受到前一個操作影響。如果操作之間可以透過其他機制互相影響,那麼可以說它們有隱性的依賴關係。透過揭發這些隱性的依賴關係,可以提升程式的參考透明性。越有參考透明性的程式碼越容易閱讀與重構,只要透過依賴關係就能了解它們之間是如何互相影響。參考透明原則強調操作之間的依賴關係,暴露隱含的依賴關係會讓程式看起來更複雜,但如果不這麼做反而會使程式更容易出錯,更容易出現詭異的相互作用。


單一情境原則(single context principle)認為變數、類型、介面等實體的定義與應用應該盡量限定於單一情境上。定義類型時它的行為是根據其意義所決定的,而情境越單一,語義就越明確。一般用途的類型包含很多相關函式,但並不是所有的函式都適用於所有情境下,例如位元移位運算子並不適用於表示數量的變數,就算你只是打算乘以二也不該這麼做。一般來說,我們可以藉由浮點數描述某個物件的實際長度,但前提是我們必須知道你指的是在哪個單位下。如果只是在小範圍使用,我們可以在變數上標註單位以描述情境。但如果它和多個函式相關,最好定義新的類型包裝起來,並在此類型的說明文件上描述使用情境。透過將浮點數包進一個類型,我們可以賦予實際長度的語義給這個數字,讓這個變數的使用情境更明確。我們常用整數的正負號當作比較順序的結果,更好的方式應該是定義專用的列舉表示順序。例如rust定義Ordering以表示比較順序,同時還能提供串聯和反轉等輔助方法,這歸功於更明確的類型和語義。類似的,findIndex的方法常以回傳負數代表找不到,這也是把整數用做多個情境的問題,這種條件式情境可以透過代數資料類型描述,例如可以像rust使用Option明確將不同的狀況分離開來。如果狀況很複雜以至於無法單純用代數資料類型描述,就必須寫一長串說明文字描述可能的狀況和應該要怎麼使用,這時我們應該透過類型將各種情境分離開來,盡量讓不合法的使用方式變得看起來不合理,就像電腦上的各種接線都有不同的形狀一樣。物件導向則傾向將複雜的狀況封裝起來,並用動態的方式管理狀態,但這樣會使其缺乏彈性,而且很容易會為了合法性重複檢查相同的判斷式。物件導向定義類別往往是為了封裝,但這個原則認為應該要為了描述情境和語義而定義類型,並透過類型說話而非文件。總結來說,單一情境原則專注於語義的情境,透過分離情境可以讓語義更明確,使得不合法的狀況看起來不合理。


我認為這三個原則可以描述函數式編程的風格,第二個是我自己延伸自參考透明的特性,第三個是我從類型驅動編程抽取出來的概念。這套定義或許和多數人對於函數式編程的印象很不一樣,尤其是在javascript學函數式編程的人,但這就是我總結我使用函數式程式語言的經驗所得到的結論。


4會員
28Content count
這不是教你如何從物件導向到函數式編程的入門教程。我會深入探討物件導向與函數式編程的差異,並討論為什麼你應該使用函數式編程並徹底放棄物件導向。
留言0
查看全部
發表第一個留言支持創作者!
have bear的沙龍 的其他內容
前面談了那麽多函數式編程與物件導向的差異,但我們還沒定義函數式編程。就像物件導向,函數式編程沒有明確的定義,每個人對於什麼是函數式編程都有不同的看法。在這裡我會總結前面的討論,給出我對於函數式編程的觀點。 物件導向注重封裝與延展性,因此一般基於三個機制:繼承、多型、封裝,它們代表了物件導向所重
說到物件導向就必須提五個原則,統稱SOLID,它被認為是物件導向的重要概念。這五個原則並不只適用於物件導向,事實上它很像函數式編程的習慣。它的命名很奇怪且容易讓人混淆,所以我會用我自己的翻譯解釋。 Single Responsibility Principle 是「單一職責原則」,認為一個模組
讓我在這篇文章總結一下前面對物件導向設計的討論,我們討論了物件導向的四個特性:繼承、抽象、多型、封裝,分析了它們的問題,並跟函數式編程的思維做比較。我們引入了與之相對應的特性:泛型、特性系統、模組化,有些特性雖然跟那四個特性很像,但在一些細微的地方有不同的詮釋,使得整體思考方式很不一樣。 「繼
物件導向設計的一個重點就是封裝,這有很多層面上的意義,但基本上就是控制物件的成員變數和方法的存取權。物件導向的封裝還跟繼承機制有關,這使得有一些時候我們逼不得已必須把函式定義在類別上,這種做法使得物件的功能變得難以拆解。封裝應該是模組的職責,並不需要再給物件相同的能力。 一般的模組系統就是把相
上一篇文章提到有些介面不應被繼承,但物件導向的子類別只能繼承父類別的介面,因而產生一些不合適的介面實作。trait/typeclass則沒有這種繼承機制,這似乎使需要繼承的特性無法直接使用。然而函數式導向比起繼承,更適合使用組合,根本不需要使用繼承疊加特性。 資料類型的定義往往跟怎麼建構模型相
類似於trait/typeclass的特性系統能提供程式「延展性」,它能讓函式針對不同的類型做出不同的行為。這種機制與物件導向的繼承非常像,然而特性系統的彈性比較大一點,而且概念上也有一些差別。為了探討討論這些差異,我們必須深入了解繼承機制到底是什麼。 繼承並不是建立子類關係的唯一方法。所謂的
前面談了那麽多函數式編程與物件導向的差異,但我們還沒定義函數式編程。就像物件導向,函數式編程沒有明確的定義,每個人對於什麼是函數式編程都有不同的看法。在這裡我會總結前面的討論,給出我對於函數式編程的觀點。 物件導向注重封裝與延展性,因此一般基於三個機制:繼承、多型、封裝,它們代表了物件導向所重
說到物件導向就必須提五個原則,統稱SOLID,它被認為是物件導向的重要概念。這五個原則並不只適用於物件導向,事實上它很像函數式編程的習慣。它的命名很奇怪且容易讓人混淆,所以我會用我自己的翻譯解釋。 Single Responsibility Principle 是「單一職責原則」,認為一個模組
讓我在這篇文章總結一下前面對物件導向設計的討論,我們討論了物件導向的四個特性:繼承、抽象、多型、封裝,分析了它們的問題,並跟函數式編程的思維做比較。我們引入了與之相對應的特性:泛型、特性系統、模組化,有些特性雖然跟那四個特性很像,但在一些細微的地方有不同的詮釋,使得整體思考方式很不一樣。 「繼
物件導向設計的一個重點就是封裝,這有很多層面上的意義,但基本上就是控制物件的成員變數和方法的存取權。物件導向的封裝還跟繼承機制有關,這使得有一些時候我們逼不得已必須把函式定義在類別上,這種做法使得物件的功能變得難以拆解。封裝應該是模組的職責,並不需要再給物件相同的能力。 一般的模組系統就是把相
上一篇文章提到有些介面不應被繼承,但物件導向的子類別只能繼承父類別的介面,因而產生一些不合適的介面實作。trait/typeclass則沒有這種繼承機制,這似乎使需要繼承的特性無法直接使用。然而函數式導向比起繼承,更適合使用組合,根本不需要使用繼承疊加特性。 資料類型的定義往往跟怎麼建構模型相
類似於trait/typeclass的特性系統能提供程式「延展性」,它能讓函式針對不同的類型做出不同的行為。這種機制與物件導向的繼承非常像,然而特性系統的彈性比較大一點,而且概念上也有一些差別。為了探討討論這些差異,我們必須深入了解繼承機制到底是什麼。 繼承並不是建立子類關係的唯一方法。所謂的
你可能也想看
Thumbnail
1.加權指數與櫃買指數 週五的加權指數在非農就業數據開出來後,雖稍微低於預期,但指數仍向上噴出,在美股開盤後於21500形成一個爆量假突破後急轉直下,就一路收至最低。 台股方面走勢需觀察週一在斷頭潮出現後,週二或週三開始有無買單進場支撐,在沒有明確的反轉訊號形成前,小夥伴盡量不要貿然抄底,或是追空
Thumbnail
重點摘要: 1.9 月降息 2 碼、進一步暗示年內還有 50 bp 降息 2.SEP 上修失業率預期,但快速的降息速率將有助失業率觸頂 3.未來幾個月經濟數據將繼續轉弱,經濟復甦的時點或是 1Q25 季底附近
Thumbnail
近期的「貼文發佈流程 & 版型大更新」功能大家使用了嗎? 新版式整體視覺上「更加凸顯圖片」,為了搭配這次的更新,我們推出首次貼文策展 ❤️ 使用貼文功能並完成這次的指定任務,還有機會獲得富士即可拍,讓你的美好回憶都可以用即可拍珍藏!
「大下後,六七日不大便」,攻下後,結果又六七天沒有大便,「煩不解,腹滿者」,仍然煩躁,代表津液還沒回頭,腸子裡面仍有燥屎堵到,這是藥劑不足,下手太輕,「所以然者,又有宿食故也,宜大承氣湯」,再開大承氣湯給他,沒有關係。怎麼知道腸子裡面沒有燥屎了呢?看小便的顏色,小便的顏色從深黃變成淡黃色時就可以停藥
二五二:「陽明證」,其人善忘者,必有蓄血,所以然者,本有久瘀之血,故令善忘;矢雖鞕,大便反易,其色必黑,宜「抵當湯」下之。 「陽明證,其人善忘者,必有蓄血」,陽明病患者,常常東西記不清楚,剛剛講的可能馬上忘了,最近的事都忘了,可是很久以前的事會記得,蓄血就是身體裡面有瘀血,「所以然者,本有久瘀之血
「陽明病,不能食」,病患者不能吃東西了,這是中寒,代表腸胃不蠕動了,腸胃虛寒,「攻其熱必噦」,如果把不能食誤認為是有東西堵在腸胃中,而用寒涼的藥去攻下,像白虎湯裡的石膏、知母,其它如大黃、黃芩、黃連、茵陳、梔子、連翹、銀花、薄荷、犀角等都是寒涼的藥,胃會更寒,就不停的打嗝,此為「噦」,為胃氣將絕的現
Thumbnail
#寵物溝通 案例分享 寵物:貓咪 名字:大寶
「下之後,復發汗」,攻下了以後,腸胃津液傷到了,陰虛掉了,又發汗造成陽也虛掉了,陰陽兩虛,「必振寒」,病人就會覺得身體裡面很冷,手腳冰冷的現象,「脈微細」,脈摸起來跳的很慢又很微弱,「所以然者,以內外俱虛故也」,造成這樣的原因是內外都虛掉了,這時候就會用到「四逆湯」來救逆。
倪氏曰:裡虛不能發汗的情況又有表證時應該怎麼辦?就用「小建中湯加黃耆」,黃耆可以固表補氣,讓三焦通道暢通,屬於氣藥,走表,目的就是減少發汗,先把裡扶正而發一點表。
Thumbnail
作為溝通社團的一員,其實我原本以為自己在裡頭的定位會是像年輕時一樣是個激進份子,但1124的結果令我的心態轉變了不少。不論是看待社運、看待政治的操作與許多人口中的「政治酬庸」,我以前宛如「左膠」般的鋒利被磨平,逐漸把自己的思想核心拉回到左與右的中心,也就是為自己的政治意念取得平衡。
Thumbnail
1.加權指數與櫃買指數 週五的加權指數在非農就業數據開出來後,雖稍微低於預期,但指數仍向上噴出,在美股開盤後於21500形成一個爆量假突破後急轉直下,就一路收至最低。 台股方面走勢需觀察週一在斷頭潮出現後,週二或週三開始有無買單進場支撐,在沒有明確的反轉訊號形成前,小夥伴盡量不要貿然抄底,或是追空
Thumbnail
重點摘要: 1.9 月降息 2 碼、進一步暗示年內還有 50 bp 降息 2.SEP 上修失業率預期,但快速的降息速率將有助失業率觸頂 3.未來幾個月經濟數據將繼續轉弱,經濟復甦的時點或是 1Q25 季底附近
Thumbnail
近期的「貼文發佈流程 & 版型大更新」功能大家使用了嗎? 新版式整體視覺上「更加凸顯圖片」,為了搭配這次的更新,我們推出首次貼文策展 ❤️ 使用貼文功能並完成這次的指定任務,還有機會獲得富士即可拍,讓你的美好回憶都可以用即可拍珍藏!
「大下後,六七日不大便」,攻下後,結果又六七天沒有大便,「煩不解,腹滿者」,仍然煩躁,代表津液還沒回頭,腸子裡面仍有燥屎堵到,這是藥劑不足,下手太輕,「所以然者,又有宿食故也,宜大承氣湯」,再開大承氣湯給他,沒有關係。怎麼知道腸子裡面沒有燥屎了呢?看小便的顏色,小便的顏色從深黃變成淡黃色時就可以停藥
二五二:「陽明證」,其人善忘者,必有蓄血,所以然者,本有久瘀之血,故令善忘;矢雖鞕,大便反易,其色必黑,宜「抵當湯」下之。 「陽明證,其人善忘者,必有蓄血」,陽明病患者,常常東西記不清楚,剛剛講的可能馬上忘了,最近的事都忘了,可是很久以前的事會記得,蓄血就是身體裡面有瘀血,「所以然者,本有久瘀之血
「陽明病,不能食」,病患者不能吃東西了,這是中寒,代表腸胃不蠕動了,腸胃虛寒,「攻其熱必噦」,如果把不能食誤認為是有東西堵在腸胃中,而用寒涼的藥去攻下,像白虎湯裡的石膏、知母,其它如大黃、黃芩、黃連、茵陳、梔子、連翹、銀花、薄荷、犀角等都是寒涼的藥,胃會更寒,就不停的打嗝,此為「噦」,為胃氣將絕的現
Thumbnail
#寵物溝通 案例分享 寵物:貓咪 名字:大寶
「下之後,復發汗」,攻下了以後,腸胃津液傷到了,陰虛掉了,又發汗造成陽也虛掉了,陰陽兩虛,「必振寒」,病人就會覺得身體裡面很冷,手腳冰冷的現象,「脈微細」,脈摸起來跳的很慢又很微弱,「所以然者,以內外俱虛故也」,造成這樣的原因是內外都虛掉了,這時候就會用到「四逆湯」來救逆。
倪氏曰:裡虛不能發汗的情況又有表證時應該怎麼辦?就用「小建中湯加黃耆」,黃耆可以固表補氣,讓三焦通道暢通,屬於氣藥,走表,目的就是減少發汗,先把裡扶正而發一點表。
Thumbnail
作為溝通社團的一員,其實我原本以為自己在裡頭的定位會是像年輕時一樣是個激進份子,但1124的結果令我的心態轉變了不少。不論是看待社運、看待政治的操作與許多人口中的「政治酬庸」,我以前宛如「左膠」般的鋒利被磨平,逐漸把自己的思想核心拉回到左與右的中心,也就是為自己的政治意念取得平衡。