top of page
31384208_181028232712608_756107685128044544_n.jpg

What is monad?
A monad is just a monoid in the category of endofunctors, what's the problem?

今天我們要介紹的是在泛函編程裡“惡名昭彰”的Monad(單子)。Monad這個詞最早出現於萊布尼茨的單子論,是萊布尼茨的哲學思想精髓。萊佈尼茲定義單子為一切事物的形上學基本元素,無限數量的單子充斥於時空,單子互相嵌合影響所形成的整體感知呈現。

不過此Monad非彼Monad。我們要談的是來自於範疇論的名詞。當然從範疇論出發可以最確實的理解與感受Monad,可是理解的操作性意義可以從比較應用的角度理解。

考慮定義域為實數的函數f(x)=sqrt(x),當x>=0的時候不會有什麼問題,可是如果x<0的話(不考慮複數)就會發生錯誤。解決方法之一是放著讓程式自己因出錯終止(常出現的壞習慣)或是讓程式提出(raise)錯誤信息。這些方法以泛函編程的觀點來說實屬缺乏。這時候可以定義一個新的函式f(x)=safeSqrt(x),當x>=0時,safeSqrt回傳sqrt(x),x<0時回傳Nothing。這時候我們輸入的形態在輸出時被“裝飾”成了新的形態。

 

f∷a→b, fSafe∷a→mb

 

提到函式作重要的感念是函式的合成。例如對f=1/x及g=x+1進行合成得到=1/(x+1)。這時候就有個問題了,如果要合成的函式輸出被修飾過,就無法順利的合成了!

f∷a→mb, g∷b→mc

這時候Monad就出來解決問題了。Monad提供了被“裝飾”的函式能夠順利合成的方法。

f∷a→b, g∷b→c, f∙g∷a→c

f∷a→mb, g∷b→mc, f>=>g∷a→mc

 

這個就是Monad在泛函編程裡的重要性:提供被修飾函式順利合成的方法及概念。

有些眼尖的讀者也許發現了我沒有解釋Monad如何解決函式的合成問題還有>=>是個什麼玩意。不急,這就解釋。首先讓我們看看>=>符號的功能

(>=>)∷(a→mb)→(b→mc)→(a→mc)

 

>=>將兩個被裝飾過的函式合成新的裝飾函式,如果把裝飾的形態mb想象成是個盒子m裝著形態b的球。如果你要把函式g作用在b上面使它成為mc,其實就是要把盒子裡的b取出,將g作用於b,再將結果(mc)放回盒子。以上的的過程稱為fmap。

 

可是這還沒完成,放回盒子的東西變成mc,包含盒子就是m(mc)所以還要另外的操作將mc取出盒子,才能夠真的完成合成從a變成mc,而這個操作稱為join。

以整個過程完整的變化如下圖所示:

2021-09-23_16-00-34.png
bottom of page