前兩天講了 Functor 是一個計算語境,包含 context、可以被 map over;Applicative 是加強版的 Functor,可以應用(apply)在 context 中的函數在 context 中的值並回傳另一個在 context 中的值
 
如果你已經消化了上述的概念,則 Monad 應該不會太難理解,因為 Monad 就是 Applicative 的再加強版。
 
一句話定義 Monad:滿足將一個吃普通值,回傳在 context 中的值的函數應用在一個在 context 中的值並回傳在 context 中的值的特性。

 
還是以 Promise 做例子:我們可以用 Promise.then 來將一個普通的函數 callback 應用在在 Promise 的裡的值,並回傳一個不在 Promise (context)裡的值:

const promise = new Promise(...)
promise.then(result => result + 10)

這樣一來的話,Promise 就有 Functor 的特性(可回去複習 Day05),可以應用一個吃普通值回傳普通值的函數到在 context 中的值。
 
不過另一個常見的 Promise 用法:

fetch('http://example.com')
  .then(response => response.json())
  .then(json => console.log(json))

resonse.json() 會回傳另一個 Promise,因此 response => response.json()吃一個普通值,回傳在 context 中的值 的函數。發現了嗎?這就是類似 Monad 的特性。而有這樣子做過的讀者應該也會發現,只要每個 callback 一直都是回傳 promise,then 就可以一直接下去,這就是 Monad 的好處:可以串接帶 context 的操作
 
我們用 async/await 改寫上面的小範例:

const response = await fetch('http://example.com')
const json = await response.json()
console.log(json)

寫起來就跟一般的同步寫法非常的像,因為 Promise 本來帶有 context ,但是 await 包裝了這個 context,所以雖然每一行都仰賴上一行的執行成功,但看起來他們卻是屬於同一個層級,不用一直用 then 來串接。因此 Monad 的特性可以讓我們如流水線般操作帶有 context 的操作,加上一些語法糖就可以變成如同層級一般。  

綜合懶人包

  • Functor :應用一個函數在 context 中的值
  • Applicative :應用一個在 context 中的函數在 context 中的值
  • Monad :應用一個接收普通值但是回傳一個在 context 中的值的函數到一個 在 context 中的值。 
     

系列文的最後一篇,也是 Functor/Applicative/Monad 三部曲的最終章。相信大部分的讀者讀到今天,應該仍然還是一臉矇逼,覺得我到底看了三小,這也是我第一次讀 《Haskell趣學指南》 時的心情。

 
老實說 Functional Programming 的整個概念思維,跟 OOP 或著所謂的 Imperative Programming 的概念完全不同,是一套很不相容的思維體系了。說實在話我也不認為後半段講的這些特性,在近未來我會有機會直接用在任何 production use 上。不過藉由學習 FP 的精神跟設計,可以開啟新的視野,更了解計算的本質,而且可以重新認知在 OOP 或 Imperative Programming 裡的一些名詞。
 
誠摯的推薦如果看完了這一系列文章,對 Functional Programming 開始感到有興趣(或著熱情還沒被澆熄XD)的人可以考慮學一下 haskell (《Haskell趣學指南》是一個很好的入門資源),然後想對 Functor/Applicative/Monad 有更深理解的話,可以參考 Functor、Applicative 和 Monad,本系列的文章有很大部分參考這篇文章,有精美的插圖及詳細的解釋。
 
希望看完整系列的讀者能稍微感受到 Functional Programming 的魔力 XD

#Functional Programming #程式設計







你可能感興趣的文章

第一次學習 Shell Script - 隨手記

第一次學習 Shell Script - 隨手記

querySelector 和 getElement 差別

querySelector 和 getElement 差別

Aspect-Oriented Programming(AOP) 面向導向程式

Aspect-Oriented Programming(AOP) 面向導向程式






留言討論