所以Monad到底是什麼 — typeclass

更新於 發佈於 閱讀時間約 6 分鐘

如果你曾經試圖學習函數式編程,並嘗試理解Monad,但看到文件上的定義卻一個字都看不懂,使用的術語、概念和一般常見的語言又很不一樣。網路上的教程往往都是以最簡單的範例試圖解釋Monad,但看到實際案例後又發現你完全不懂。事實上大部分教程的描述並不適用於「所有」的Monad,甚至在某方面來說是錯的,就算有正確的描述,從軟體開發的角度仍然難以理解。我所謂的「軟體開發的角度」是指:當我們處理資料時,會試圖找實際案例理解資料的意義,這麼做能處理哪些狀況,遇到這個例外時又要怎麼辦。這種由下而上、窮舉式的思考是最實際解決問題的方法,然而Monad官方說明文件卻從不告訴你他是什麼,也從不說明遇到某些情況時為什麼仍沒有問題,這讓工程師無所適從,至少我曾經是如此。這個系列的文章目的是希望能從軟體開發的角度理解Monad等typeclass的概念,並試圖把所有我能想到的、遇到的、跟找得到的各種範例與反例一一展開討論,透過它們循序漸進地打破與重建我們對於Monad的印象。其中將以PureScript編寫範例,簡單來說它就是拿掉惰性求值的比較好的 haskell,其程式碼可以轉譯成有意義的js。

Monad 是函數式編程中很重要的概念,很多我們習以為常的指令式操作在純函數式程式語言中必須使用Monad實現,這使得純函數式編程的使用體驗與其他程式語言很不一樣。這並不是因為純函數式程式語言設計的很爛(至少這方面不是如此),而是它把我們之前沒有注意到習以為常的特性明確地展示出來(unknown known);複雜的不是Monad,而是被我們忽略掉的指令式編程的基本結構。因此Monad是進階函數式編程中最重要的概念,也是讓我們重新認識指令式編程的絕佳機會。要了解Monad,就要先談談函數式編程與眾不同的多型機制:typeclass。typeclass是haskell/PureScript實現根據類型而產生不同行為的唯一機制,這個能力類似於物件導向的子類機制,它們常常被用來實現抽象化的行為。事實上並不是只有子類關係和typeclass能夠描述抽象化,程式裡面處處是不同程度的抽象化。

當我們把一段重複出現的程式碼抽離出來共用,並把其中不一樣的地方改成參數,這個過程抹除了參數的實際數值,因此函式是計算過程對於這些變數的抽象化。

當我們處理某些業務邏輯的計算問題時,需要使用一些區域變數暫存一些業務資料,而不論這個資料代表什麼,通常會直接使用已有的基礎結構如List a, Map k v,這些結構本身並不帶有如業務邏輯的實際意義,而是根據使用方式決定意義,因此可以說這些通用容器類是資料對於意義的抽象化。

有時我們並不關心類型的實際結構(例如各種資料庫、各種容器類)而只在意行為(一系列的關聯方法),並希望不同結構但擁有相同行為的物件能夠在相同情況下被使用,而不需要重複編寫幾乎一樣的程式碼,這可以透過介面、typeclass實現,這種介面是物件行為對於實際類型的抽象化。

一些不同的抽象行為也有共通性,例如擁有狀態的操作可以抽象化成定義存取狀態方法的介面,而能夠執行平行運算的操作也可以抽象化成定義派發平行運算任務方法的介面,這兩種介面擁有共通性質:擁有可嵌套的情境,稱為Monad。執行一系列改變狀態的操作可看作一個普通的改變狀態的操作,而在平行執行緒中派發平行運算的任務理想情況下可看作普通地執行平行運算的操作。Monad只在意能否嵌套,實際上在做什麼並不是重點,只要符合特定規則就是一種Monad,這屬於規則對於實際能力的抽象化。

Functor, Applicative, Monad等都是最後一種類型的抽象化,它與我們一般使用介面的方法很不一樣,它描述的是規則而非業務邏輯的抽象化。在類型驅動編程中,我們會使用類型或介面描述特定概念,例如定義Point3D為帶有三個浮點數的結構以代表三維空間中的點,就算已經有一個類型Vector3D也應該這麼做,因為它們是不同的概念。即使我們對這個概念擁有什麼方法,遵守哪些規則都不清楚,也應該這麼做。例如rust的Pin就是如此,它只告訴你要自己定義各個成員的映射方法,要不然根本沒辦法用,真正重要的是它所代表的概念。而Functor、Monad等則恰恰相反,它們只關心規則,只要符合它所定義的規則,就是合法的實作。事實上它們的目的本來就不是抽象化某個概念,而是用來限定類型必須符合某種規則,因此不應該使用原本對介面的理解方式來認識它們。

你可能會想functor, monad, comonad等typeclass所定義的函式與規則實際上並不能做什麼,因為它們只描述了最最基本的特性,而更進一步的特性才能賦予我們操作的能力。我們應該把它當作「限制」而非「能力」,因此這句話就變成:它們只做了非常基本的限制,就能適用於非常多的地方。這點顯示了type class/trait與我們一般認知的interface/ability之間觀點的差異。函數式編程往往只透過限制基本規則來定義通用函式,而非把他當作某種抽象概念的延伸。因此如果要使用某個函式,只要看它符合哪些規則,如果你的情境符合這個規則,就可以根據要求實作相應的typeclass並使用它,而不需要擔心它所代表的概念是否適用於此。這種typeclass強調的是規則、結構,並沒有特別描述什麼概念,而軟體開發所使用interface的方法則更強調抽象概念。如果你從haskell跳到rust就必須注意這一點,haskell以規則為核心,而rust雖然有類似的類型系統,但是那些都是為概念服務的,因此會出現很多複雜的規則,只為了讓它心目中的概念可以運作。

即使這類的typeclass在定義上把實作時該符合哪些規則都寫得清清楚楚,單從規則很難想像他到底是什麼,很容易就會被已知的情報所困住,因而陷入既定印象。例如一般都會把functor描述成容器,因為List, Maybe, Map k等容器都會實作functor,然而不是容器的Function a也實作了functor,因此這並不是合適的描述*。如果沒有人告訴你這些例子,一般是很難自己意識到這種偏見,因此認識這類的typeclass需要更多實例幫助理解,尤其是反例,藉由反問哪些不符合這個規則或是印象,可以更加理解他所代表的概念的邊界。

留言
avatar-img
留言分享你的想法!
avatar-img
have bear的沙龍
4會員
28內容數
這不是教你如何從物件導向到函數式編程的入門教程。我會深入探討物件導向與函數式編程的差異,並討論為什麼你應該使用函數式編程並徹底放棄物件導向。
你可能也想看
Thumbnail
介紹朋友新開的蝦皮選物店『10樓2選物店』,並分享方格子與蝦皮合作的分潤計畫,註冊流程簡單,0成本、無綁約,推薦給想增加收入的讀者。
Thumbnail
介紹朋友新開的蝦皮選物店『10樓2選物店』,並分享方格子與蝦皮合作的分潤計畫,註冊流程簡單,0成本、無綁約,推薦給想增加收入的讀者。
Thumbnail
當你邊吃粽子邊看龍舟競賽直播的時候,可能會順道悼念一下2300多年前投江的屈原。但你知道端午節及其活動原先都與屈原毫無關係嗎?這是怎麼回事呢? 本文深入探討端午節設立初衷、粽子、龍舟競渡與屈原自沉四者。看完這篇文章,你就會對端午、粽子、龍舟和屈原的四角關係有新的認識喔。那就讓我們一起解開謎團吧!
Thumbnail
當你邊吃粽子邊看龍舟競賽直播的時候,可能會順道悼念一下2300多年前投江的屈原。但你知道端午節及其活動原先都與屈原毫無關係嗎?這是怎麼回事呢? 本文深入探討端午節設立初衷、粽子、龍舟競渡與屈原自沉四者。看完這篇文章,你就會對端午、粽子、龍舟和屈原的四角關係有新的認識喔。那就讓我們一起解開謎團吧!
Thumbnail
1.0 從函數到函算語法 1.4 函算語法 1.4.1 語法範疇理論導論 1.4.2 函算語法與函數概念 四 在以語構範疇為單位的語言結構上,同樣可以應用前述的函數概念或規則。其中一個最大的分別是,若以 1.4.2_4 為用作對比的例子,函算語法的論域 (domain of dis
Thumbnail
1.0 從函數到函算語法 1.4 函算語法 1.4.1 語法範疇理論導論 1.4.2 函算語法與函數概念 四 在以語構範疇為單位的語言結構上,同樣可以應用前述的函數概念或規則。其中一個最大的分別是,若以 1.4.2_4 為用作對比的例子,函算語法的論域 (domain of dis
Thumbnail
1.0 從函數到函算語法 1.4 函算語法 1.4.1 語法範疇理論導論 1.4.2 函算語法與函數概念 三 弗雷格從語言結構的觀點出發,提出了函數可以被視為一個不完整的表式。如果我們將一個函數拆解為一個由一個函子及其 (一個或多個) 論元所組成的表式,那麼該函子便是一個有待滿足的
Thumbnail
1.0 從函數到函算語法 1.4 函算語法 1.4.1 語法範疇理論導論 1.4.2 函算語法與函數概念 三 弗雷格從語言結構的觀點出發,提出了函數可以被視為一個不完整的表式。如果我們將一個函數拆解為一個由一個函子及其 (一個或多個) 論元所組成的表式,那麼該函子便是一個有待滿足的
Thumbnail
1.0 從函數到函算語法 1.4 函算語法 1.4.1 語法範疇理論導論 1.4.2 函算語法與函數概念 二 關於函數的演變和弗雷格對函數的看法,前面的 1.2 節和 1.3 節已經談論了不少。 由於函數在數學﹑邏輯學﹑計算語言學極為重要,更且是本書闡述的語法的中心概念,因此有必要再略作
Thumbnail
1.0 從函數到函算語法 1.4 函算語法 1.4.1 語法範疇理論導論 1.4.2 函算語法與函數概念 二 關於函數的演變和弗雷格對函數的看法,前面的 1.2 節和 1.3 節已經談論了不少。 由於函數在數學﹑邏輯學﹑計算語言學極為重要,更且是本書闡述的語法的中心概念,因此有必要再略作
Thumbnail
1.0 從函數到函算語法 1.4 函算語法 1.4.1 語法範疇理論導論 七 指派範疇是第一步, 第二步是設定推導規則。 推導規則的作用是對某一給定的表式63 進行判定,看它是否一個貫通的表式(或詞構)。就上述英語例句而言,我們只需一個簡單的單向通則 (general rule)﹕6
Thumbnail
1.0 從函數到函算語法 1.4 函算語法 1.4.1 語法範疇理論導論 七 指派範疇是第一步, 第二步是設定推導規則。 推導規則的作用是對某一給定的表式63 進行判定,看它是否一個貫通的表式(或詞構)。就上述英語例句而言,我們只需一個簡單的單向通則 (general rule)﹕6
Thumbnail
1.0 從函數到函算語法 1.2 函數概念小史 1.2.1 中譯的來源 1.2.2 一個速度問題 1.2.3 幾何的方法 1.2.4 微積分的記法 1.2.5 弦的振動 1.2.6 熱的傳導 1.2.7 十九世紀的尾聲 三 必須說一下波希米亞數學家/邏輯學家/哲學家/神學
Thumbnail
1.0 從函數到函算語法 1.2 函數概念小史 1.2.1 中譯的來源 1.2.2 一個速度問題 1.2.3 幾何的方法 1.2.4 微積分的記法 1.2.5 弦的振動 1.2.6 熱的傳導 1.2.7 十九世紀的尾聲 三 必須說一下波希米亞數學家/邏輯學家/哲學家/神學
Thumbnail
1.0 從函數到函算語法 1.2 函數概念小史 1.2.1 中譯的來源 1.2.2 一個速度問題 1.2.3 幾何的方法 1.2.4 微積分的記法 1.2.5弦的振動  七 雖然論爭沒有得出任何定論,但對函數概念的演化卻影嚮頗深。 在這次歷時多年的論爭中,函數概念得以擴大而包括
Thumbnail
1.0 從函數到函算語法 1.2 函數概念小史 1.2.1 中譯的來源 1.2.2 一個速度問題 1.2.3 幾何的方法 1.2.4 微積分的記法 1.2.5弦的振動  七 雖然論爭沒有得出任何定論,但對函數概念的演化卻影嚮頗深。 在這次歷時多年的論爭中,函數概念得以擴大而包括
Thumbnail
1.0 從函數到函算語法 1.2 函數概念小史 1.2.1 中譯的來源 1.2.2 一個速度問題 1.2.3 幾何的方法 1.2.4 微積分的記法 1.2.5 弦的振動 五 特朗貝爾依循當時數學界對函數的普遍理解,視「函數」為任一分析式。 但這時的歐拉宣稱函數不必是正常意義下的
Thumbnail
1.0 從函數到函算語法 1.2 函數概念小史 1.2.1 中譯的來源 1.2.2 一個速度問題 1.2.3 幾何的方法 1.2.4 微積分的記法 1.2.5 弦的振動 五 特朗貝爾依循當時數學界對函數的普遍理解,視「函數」為任一分析式。 但這時的歐拉宣稱函數不必是正常意義下的
Thumbnail
1.0 從函數到函算語法 1.2 函數概念小史 1.2.1 中譯的來源 數學中函數概念的重要性難以盡書,亦很難想像沒有函數概念的數學可以走多遠。誇張一點,我們可以說很大部份的數學都是按函數概念操作的。但少有人留意到,在某個意義上,函數可說是數學語言的一個語構處理。 漢語「函數」一詞乃
Thumbnail
1.0 從函數到函算語法 1.2 函數概念小史 1.2.1 中譯的來源 數學中函數概念的重要性難以盡書,亦很難想像沒有函數概念的數學可以走多遠。誇張一點,我們可以說很大部份的數學都是按函數概念操作的。但少有人留意到,在某個意義上,函數可說是數學語言的一個語構處理。 漢語「函數」一詞乃
Thumbnail
1.0 從函數到函算語法 1.1 句子成份 本書關注的是句子成份的分析。 如前述,詞類和句子成份是兩個很不一樣的概念。 詞類的劃分屬歸類性的描述。我們先有一個給定的詞彙,然後劃分若干詞類,比如名詞﹑動詞﹑形容詞等,再進而對詞彙中的每一個詞進行分類,即說某詞屬名詞﹑某詞屬動詞﹑某詞可以是名
Thumbnail
1.0 從函數到函算語法 1.1 句子成份 本書關注的是句子成份的分析。 如前述,詞類和句子成份是兩個很不一樣的概念。 詞類的劃分屬歸類性的描述。我們先有一個給定的詞彙,然後劃分若干詞類,比如名詞﹑動詞﹑形容詞等,再進而對詞彙中的每一個詞進行分類,即說某詞屬名詞﹑某詞屬動詞﹑某詞可以是名
Thumbnail
目錄 序 導論: 一個西方觀點的評述 1.0 從函數到函數算法 ......1.1 句子成份
Thumbnail
目錄 序 導論: 一個西方觀點的評述 1.0 從函數到函數算法 ......1.1 句子成份
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News