iT邦幫忙

2023 iThome 鐵人賽

DAY 28
0
Software Development

Haskell 從入門到放棄系列 第 28

[Haskell 從入門到放棄] Day 27 - Monad (5)

  • 分享至 

  • xImage
  •  

Writer Monad

不知道讀者有沒有想過,如果今天我想要把每一步 monadic 操作的過程都有 log 紀錄方便我們 debug 的話要怎麼做?(print 大法也不是不行)

Writer 可以協助我們達成這方面的事情,我們可以利用它將每次計算的額外結果記錄起來並帶到下一次計算。

newtype Writer w a = Writer { runWriter :: (a, w) }

instance (Monoid w) => Monad (Writer w) where  
    return x = Writer (x, mempty) 
    (Writer (x,v)) >>= f = let (Writer (y, v')) = f x in Writer (y, v `mappend` v')

首先這邊利用 newtype 封裝了這個型別也就是 (a,w) 這種形式,且提供 runWriter 讓我們取值。

它對於 Monad 實作說明了, m (也就是通常拿來做 log 的部分)要是 Monoid ,至於為什麼要是 Monoid 呢?因為 monoid 的 identity 的特性所以我們可以將 return x (或者想像成預設的 context )變成 Writer (x, mempty) ,這樣子我們就能確保之後不管是什麼值用 mappend 進行運算,結果都會是我們傳進來的值。

>>= 則是利用 pattern matching 將 f x 計算的結果把 y , v' 取出來並將 y 以及 v' mappend v' ,塞回去 context 。

我們先來寫一個小 function 來表示一個 Int 被裝進去 Writer 後要有一個 log

logNumber :: Int -> Writer [String] Int  
logNumber x = writer (x, ["Got number: " ++ show x])

writerWriter 所提供的 function ,當然也可以直接用 return x 來 wrap 後,再添加 log 來達成一樣的效果

然後寫計算這種 monadic value 的 function

addWithLog :: Writer [String] Int -> Writer [String] Int -> Writer [String] Int
addWithLog a b = do
  x <- a
  y <- b
  tell ["added "++ show x ++ " and " ++ show y]
  return (x + y)

這邊的程式碼就蠻簡單的,就單純的把 ab 這兩個 monadic value 從 context 取出來後,利用 tell 添加 log ,然後再用 return 包裝一次 context,至於 tell 簡單來說就是一個添加 log 的 function 。

我們來實際跑跑看

print $ runWriter $ addWithLog (logNumber 10) (logNumber 1)
-- (11,["Got number: 10","Got number: 1","added 10 and 1"])

print $ runWriter $ addWithLog (logNumber 1) $ addWithLog (logNumber 2) (logNumber 3)
-- (6,["Got number: 1","Got number: 2","Got number: 3","added 2 and 3","added 1 and 5"])

結果如我們預期的那樣,我們每次獲得數字以及運算的結果都有寫進去 Writer 裡。


今天的程式碼
https://github.com/toddLiao469469/30days-for-haskell


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

尚未有邦友留言

立即登入留言