2015-11-23 43 views
1

我正在学习Writer Monad的书“学习你一个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) 

当运行multWithLog,这是结果:

*Main> runWriter multWithLog 
(15,["Got number: 3","Got number: 5"]) 

在此行:

a <- logNumber 3 
b <- logNumber 5 

这是很容易看到那a = 3b = 5,因为他们都在倍增return函数。

我不明白的是为什么这些值是35ab是否应该包含在Writer Monad中的值?在这种情况下元组?

例如,这是与Maybe单子,ab35

do 
    a <- Just 3 
    b <- Just 5 
    return (a * b) 

在这种情况下,对我来说很有意义,因为ab收到内部Just内容。但以最初的例子,ab只接收部分值。

+0

当您在'Writer' monad中执行'x <-e'时,'x'通常不会捕获编写器状态。您可以将logNumber重写为“logNumber num = tell”...“>> return num” - 这是一个计算结果,它产生的数字与它给出的数字相同,但作为副作用“记录”了一个字符串。当你“绑定”你正在访问“返回”的值 - 这只是数字。你可以用'listen'得到想要的行为:'(x,loggedString)< - listen $ logNumber 3'。 – user2407038

回答

2

很容易看出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) 

正如你可以在实例方法见>>=,功能f适用于a值,而不是整个元组。语法a <- logNumber 3使用>>=解除绑定,因此绑定到a的值将是Writer所包含的元组的第一个元素。

2

“包含在monad中的想法有点模糊。它有点作品,但并不严格。

真的,一个monad本身不包含“包含”任何东西。这是not actually a spacesuit or burrito,你知道...

Writer的情况下,你能说清楚,这是一个型其值同时​​包含日志段和计算,结果。后者是您可能会解释的单子的“内容”,您可以使用a <-来检索。但总的来说,根本不需要任何这样的内容。

事实上,留在你的Maybe例如:

do a <- Just 3 
    Nothing 
    b <- Just 5 
    return (a * b) 

在这种情况下,Nothing “中断”计算,所以Just 5没有永远能值5注入a

要记住的事情是,如果action :: M T一些单子M,然后

do 
    ... 
    a <- action 

可以给aT类型的值。(在你的榜样,MWriter [String]TInt,所以a只能有型Int。)

无论是实际发生的,多久,这里的值来自与意味着什么取决于具体的单子。不过,monad laws可以告诉你很多关于整个计算的行为。但是,在了解monad时,最好忘掉所有这些,只需看看许多不同的例子,并自己和monad打交道,在某些时候你会得到一个直觉。 Don't try too hard to “understand” monads through analogies

3

在这种情况下,对我来说很有意义,因为ab收到内部Just内容。但以最初的例子,ab只接收部分值。

这个描述没有什么错,但我们也可以用另一种方式来看待这种情况。在...

a <- Just 3 

...我们也可以说,a只接收的Just 3部分 - Just包装没有做到这一点。从这一点来看,与什么发生了......

a <- writer (3, ["Got number: " ++ show 3]) 

...颇为相似:a只接收3值。该[String]注解,如此说来,留在后台,让mappend编入彼此由一元的绑定,就像(>>=)结合Maybe这么说JustJustJustNothing与任何给Nothing