理解 Writer Monad 的例子

lha*_*ahn 3 monads haskell writer-monad

我正在通过 Learn You A Haskell 一书了解 Writer Monad。

这是一段代码:

import Control.Monad.Writer

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

multWithLog :: Writer [String] Int
multWithLog = do
  a <- logNumber 3
  b <- logNumber 5
  return (a * b)
Run Code Online (Sandbox Code Playgroud)

运行时multWithLog,结果如下:

*Main> runWriter multWithLog
(15,["Got number: 3","Got number: 5"])
Run Code Online (Sandbox Code Playgroud)

在这一行:

a <- logNumber 3
b <- logNumber 5
Run Code Online (Sandbox Code Playgroud)

很容易看出a = 3and b = 5,因为它们都在return函数上相乘。

我不明白的是为什么这些值是35。不宜ab是里面包含值Writer单子?在这种情况下元组?

例如,这与MaybeMonad 一起使用,a并且b将是35

do
  a <- Just 3
  b <- Just 5
  return (a * b)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,这对我来说很有意义,因为ab接收Just. 但是,随着最初的例子,a并且b仅接收值的一部分。

Lui*_*las 5

很容易看出 a = 3 和 b = 5,因为它们都在返回函数上相乘。我不明白的是为什么这些值是 3 和 5。a 和 b 不应该是包含在 Writer Monad 中的值吗?在这种情况下元组?

不。我认为回答这个问题的最简单方法是实现Writer类型并研究它的Monad类实例:

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

instance Functor (Writer w) where
  fmap f (Writer (a, w)) = Writer (f a, w)

instance Monoid w => Applicative (Writer w) where
  pure a = Writer (a, mempty)
  Writer (f, w) <*> Writer (a, w') = Writer (f a, w <> w')

instance Monoid w => Monad (Writer w) where
  return = pure
  Writer (a, w) >>= f = let (b, w') = runWriter (f a)
                        in Writer (b, w <> w')

tell :: w -> Writer w ()
tell w = Writer ((), w)
Run Code Online (Sandbox Code Playgroud)

正如您在 的实例方法中所见>>=,该函数f应用于a值,而不是整个元组。使用 对语法a <- logNumber 3进行脱糖>>=,因此绑定到的值a将是Writer环绕的元组的第一个元素。