理解 Writer Monad 的例子
Understanding example on Writer Monad
我正在 Learn You A 一书中了解 Writer Monad Haskell。
这是一段代码:
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)
当运行multWithLog
时,结果是这样的:
*Main> runWriter multWithLog
(15,["Got number: 3","Got number: 5"])
这一行:
a <- logNumber 3
b <- logNumber 5
很容易看出 a = 3
和 b = 5
,因为它们都在 return
函数上相乘。
我不明白的是为什么这些值是 3
和 5
。 a
和 b
不应该是 Writer
Monad 中包含的值吗?在这种情况下元组?
例如,对于 Maybe
Monad,a
和 b
将是 3
和 5
:
do
a <- Just 3
b <- Just 5
return (a * b)
在这种情况下,这对我来说很有意义,因为 a
和 b
接收 Just
中的内容。但是对于初始示例,a
和 b
仅接收部分值。
“值包含在 monad 中”的概念有点模糊。有点效果,但不严格。
真的,这样的 monad 不“包含”任何东西。这是not actually a spacesuit or burrito,你知道...
在Writer
的情况下,你可以明确地说这是一个类型,其值包含日志片段和计算结果。后者是您可以解释为 monad 的“内容”,并且是您可以使用 a <-
检索的内容。但总的来说,根本不需要有这样的内容。
事实上,继续使用您的 Maybe
示例:
do a <- Just 3
Nothing
b <- Just 5
return (a * b)
在这种情况下,Nothing
“中断”了计算,因此 Just 5
永远无法将值 5
注入 a
。
要记住的是,如果 action :: M T
对于某些 monad M
,则
do
...
a <- action
可以给a
一个T
类型的值。 (在你的例子中,M
是 Writer [String]
而 T
是 Int
,所以 a
只能有类型 Int
。)
这是否真的发生、发生的频率、值的来源以及它的含义取决于特定的 monad。尽管如此,monad laws can tell you a lot about the whole computation will behave. But while learning about monads, it's probably best to forget about all this, simply look at many different examples and dabble with monads yourself, at some point you'll get an intuition for them. Don't try too hard to “understand” monads through analogies.
In this case it makes sense to me, since a
and b
receive the content inside Just
. But with the initial example, a
and b
only receive part of the value.
这个描述其实没有什么不妥,但是我们也可以换个角度来看这个情况。在...
a <- Just 3
...我们也可以说 a
只收到 Just 3
的一部分——Just
包装器没有做到。从这个角度来看,发生了什么...
a <- writer (3, ["Got number: " ++ show 3])
... 非常相似:a
仅接收 3
值。 [String]
注释,可以说,留在后台,通过 monadic 绑定使 mappend
相互融合,很像 (>>=)
组合 Maybe
以便 Just
与 Just
一起给出 Just
和 Nothing
与任何东西一起给出 Nothing
。
It is easy to see that a = 3 and b = 5, since both of them are being multiplied on the return function. What I don't understand is why those values are 3 and 5. Shouldn't a and b be the values that contain inside the Writer Monad? In this case tuples?
没有。我认为回答这个问题最简单的方法就是实现 Writer
类型并研究它的 Monad
class 实例:
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)
正如您在 >>=
的实例方法中看到的那样,函数 f
应用于 a
值,而不是整个元组。语法 a <- logNumber 3
使用 >>=
脱糖,因此绑定到 a
的值将是 Writer
环绕的元组的第一个元素。
我正在 Learn You A 一书中了解 Writer Monad Haskell。
这是一段代码:
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)
当运行multWithLog
时,结果是这样的:
*Main> runWriter multWithLog
(15,["Got number: 3","Got number: 5"])
这一行:
a <- logNumber 3
b <- logNumber 5
很容易看出 a = 3
和 b = 5
,因为它们都在 return
函数上相乘。
我不明白的是为什么这些值是 3
和 5
。 a
和 b
不应该是 Writer
Monad 中包含的值吗?在这种情况下元组?
例如,对于 Maybe
Monad,a
和 b
将是 3
和 5
:
do
a <- Just 3
b <- Just 5
return (a * b)
在这种情况下,这对我来说很有意义,因为 a
和 b
接收 Just
中的内容。但是对于初始示例,a
和 b
仅接收部分值。
“值包含在 monad 中”的概念有点模糊。有点效果,但不严格。
真的,这样的 monad 不“包含”任何东西。这是not actually a spacesuit or burrito,你知道...
在Writer
的情况下,你可以明确地说这是一个类型,其值包含日志片段和计算结果。后者是您可以解释为 monad 的“内容”,并且是您可以使用 a <-
检索的内容。但总的来说,根本不需要有这样的内容。
事实上,继续使用您的 Maybe
示例:
do a <- Just 3
Nothing
b <- Just 5
return (a * b)
在这种情况下,Nothing
“中断”了计算,因此 Just 5
永远无法将值 5
注入 a
。
要记住的是,如果 action :: M T
对于某些 monad M
,则
do
...
a <- action
可以给a
一个T
类型的值。 (在你的例子中,M
是 Writer [String]
而 T
是 Int
,所以 a
只能有类型 Int
。)
这是否真的发生、发生的频率、值的来源以及它的含义取决于特定的 monad。尽管如此,monad laws can tell you a lot about the whole computation will behave. But while learning about monads, it's probably best to forget about all this, simply look at many different examples and dabble with monads yourself, at some point you'll get an intuition for them. Don't try too hard to “understand” monads through analogies.
In this case it makes sense to me, since
a
andb
receive the content insideJust
. But with the initial example,a
andb
only receive part of the value.
这个描述其实没有什么不妥,但是我们也可以换个角度来看这个情况。在...
a <- Just 3
...我们也可以说 a
只收到 Just 3
的一部分——Just
包装器没有做到。从这个角度来看,发生了什么...
a <- writer (3, ["Got number: " ++ show 3])
... 非常相似:a
仅接收 3
值。 [String]
注释,可以说,留在后台,通过 monadic 绑定使 mappend
相互融合,很像 (>>=)
组合 Maybe
以便 Just
与 Just
一起给出 Just
和 Nothing
与任何东西一起给出 Nothing
。
It is easy to see that a = 3 and b = 5, since both of them are being multiplied on the return function. What I don't understand is why those values are 3 and 5. Shouldn't a and b be the values that contain inside the Writer Monad? In this case tuples?
没有。我认为回答这个问题最简单的方法就是实现 Writer
类型并研究它的 Monad
class 实例:
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)
正如您在 >>=
的实例方法中看到的那样,函数 f
应用于 a
值,而不是整个元组。语法 a <- logNumber 3
使用 >>=
脱糖,因此绑定到 a
的值将是 Writer
环绕的元组的第一个元素。