我正在从“Learn you a Haskell for Great Good”教程中学习 Haskell,并且我已经完成了关于writer monads的部分。这是我无法弄清楚的例子。
import Control.Monad.Writer
logNumber :: Int -> Writer [String] Int
logNumber x = writer (x, ["Got number: " ++ show x])
multWithLog :: Writer [String] Int
multWithLog = do
a <- logNumber 3
b <- logNumber 5
return (a*b) -- shouldn't return (3*5) result in (15,[]) ?
ghci> runWriter $ multWithLog
(15,["Got number: 3","Got number: 5"]) -- how did that happen?
我试图了解块返回w
的Writer w a
monad中的 monoidic 值是如何do
改变的。本教程没有详细说明mappend
ing 是如何发生的。
作为 monad的类型声明Writer
和实例声明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')
如果根据实例声明return x
产生结果Writer (x, mempty)
并且mempty
对于 monoid[a]
是[]
,不应该return (a*b)
,等于return (3*5)
,评估为(15,[])
?
ghci> return (15) :: Writer [String] Int
WriterT (Identity (15,[]))
我把上面的命令给了 ghci ,它返回一个WriterT
类型值,元组包含一个空列表,正如预期的那样。
multWithLog :: Writer [String] Int
multWithLog = logNumber 3 >>= (\a ->
logNumber 5 >>= (\b ->
return (a*b)))
我改用do
绑定运算符重写了该块。上面的代码给出了与教程中的原始代码相同的结果。
我的印象是>>=
只Int
3
从结果中提取logNumber 3
并将其提供给(\a -> logNumber 5 ...etc.)
,然后logNumber
在不同的值 ( 5
) 上执行函数,依此类推。这些操作是如何导致[String]
Writer monad 的部分被改变的?