iT邦幫忙

2023 iThome 鐵人賽

DAY 23
0
Software Development

Haskell 從入門到放棄系列 第 23

[Haskell 從入門到放棄] Day 23 - Monad (1)

  • 分享至 

  • xImage
  •  

在看 monad 相關的文章時不時想到一個剛開始學 FP 時聽過的笑話 「a monad is just a monoid in the category of endofunctors」 ,隨著對於 FP 的認識逐漸加深會知道這句話的確就是一個正確的廢話。

Maybe Monad

如同 FunctorMonoidSemigroupApplicative 這些抽象概念或者 typeclass 一樣, monad 本身也是一種在數學上的抽象概念。

那 monad 能做什麼事情?試想一下在我們之前使用 Applicative 我們都需要使用到 pure 讓我們把沒有 context 轉換成一樣的 context 才能方便我們接下來的計算

pure (*) <*> Just 2 <*> Just 2 -- Just 4

然而在某些情況下我們可能會遇到 function 會有失敗的可能性,所以必須使用到 MaybeApplicative 這時就顯得不太夠用。

例如這個 function

divide :: Int -> Int -> Maybe Int
divide _ 0 = Nothing
divide x y = Just (x `div` y)

我們定義了一個 divide 可以接受兩個 Int 但最後可能會是失敗的結果所以使用 Maybe ,像是除以 0 會回傳 Nothing

首先我們先來看一下這個運算子 (>>=) (唸作 Bind)

(>>=) :: (Monad m) => m a -> (a -> m b) -> m b

簡單解釋就是 (>>=) 接收 m aa → m b 最後會回傳 m b ,也就是接收一個被 Monad 所 wrap 住的 a 以及一個接收 a 並回傳被 Monad wrap 的 b 的函數,最後則回傳被 Monad wrap 的 b 。

是不是看起來有點跟 fmap 以及 <*> 有一點點像,前者在意的是我要把一個 function apply 到一個context 裡最後回傳同一種 context 的值,後者在意的是我傳入一個在 context 裡的 function 並把它給 apply 到同一種 context 的值最後回傳同一種 context 的值。

而 (>>=) 則關注在我們 function 可以不用特別拆解 context (monad)也可以將 function apply 到 context 中 。也就是說它會將 function 跟 monad 的值綁定在一起,這也是它叫做 Bind 的原因

import Control.Monad

Just 20  >>= (`divide` 10) -- Just 2
Just 20  >>= (`divide` 0)  -- Nothing
Just 20  >>= (`divide` 10) >>= (`divide` 2) -- Just 1
Just 20  >>= (`divide` 0) >>= (`divide` 2) -- Nothing

我們使用了 (>>=) 來幫我們將 Just 20 apply 到只接受 Intdivide

也就是說我們將 Just 20divide「bind」在 Monad 中,而且我們也不必手動解開 Monad 然後接下來我們就簡單讓 Monad 的值與「不在 Monad 中的值」進行運算。

那如果沒有 (>>=) 我們的程式碼會怎麼樣呢?會變成我們在做類似於

Just 20  >>= (`divide` 0) >>= (`divide` 2) -- Nothing

這種鏈式的操作實會變得很麻煩

let result =
        case 20 `divide` 0 of
          Nothing -> Nothing
          Just x ->
            case x `divide` 2 of
              Nothing -> Nothing
              y -> y

因為 divide 是會回傳 Maybe Int 所以會看到我們每次運算時都要再用 pattern matching 來檢查現在使否是 Nothing 以及拆開 Just x 然後再進行 divide 運算。


今天的程式碼:

https://github.com/toddLiao469469/30days-for-haskell


上一篇
[Haskell 從入門到放棄] Day 22 - Monoid (2)
下一篇
[Haskell 從入門到放棄] Day 24 - Monad (2)
系列文
Haskell 從入門到放棄30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言