为什么liftM不破坏环境?

Ste*_*nes 2 haskell functional-programming

我对如何liftM保留上下文感到困惑,特别是在Writermonad 的情况下.我一直在经历"让你学习哈斯克尔为伟大的好",并坚持其解释liftM.

这是一个例子:

ghci> runWriter $ liftM not $ Writer (True, "chickpeas")
(False,"chickpeas")
Run Code Online (Sandbox Code Playgroud)

我理解将函数liftM提升not到monad中的概念,将其应用于inside(True)中的值,并且对monoid("鹰嘴豆")做任何事情,或者将它与字符串("")的身份monoid结合起来.

但是,执行情况liftM如下:

liftM :: (Monad m) => (a -> b) -> m a -> m b  
liftM f m = m >>= (\x -> return (f x))
Run Code Online (Sandbox Code Playgroud)

施加fx该单子的内部值被馈送到函数是有意义的.但是,如果我执行return (f x),为什么我不能找回f x默认 monad上下文中包含的任何产生?在Writer上面的例子中,我希望runWriter $ return (f x)生成,(False, "")因为默认Writer string bool实例具有""作为其monoid值.

我错过了什么?

Dan*_*ner 5

你已经非常专注于\x -> return (f x)完全忘记m >>=它之前的那个!

你完全正确的做法return是:

Control.Monad.Writer> return (not True) :: Writer String Bool
WriterT (Identity (False,""))
Run Code Online (Sandbox Code Playgroud)

你忘记的那个是绑定,它是这样实现的(最多一些newtype和变压器废话):

m >>= f = (val', monoid <> monoid') where
    (val, monoid) = m
    (val', monoid') = f val
Run Code Online (Sandbox Code Playgroud)

monoid'部分将""在我们的情况下,但monoid意志将是"chickpeas",所以这不会丢失.详细地:

(True, "chickpeas") >>= (\x -> return (not x))
= { definition of bind }
(val', monoid <> monoid') where
    (val, monoid) = (True, "chickpeas")
    (val', monoid') = (\x -> return (not x)) val
= { substitute away val and monoid everywhere }
(val', "chickpeas" <> monoid') where
    (val', monoid') = (\x -> return (not x)) True
= { evaluate the lambda and not }
(val', "chickpeas" <> monoid') where
    (val', monoid') = return False
= { definition of return }
(val', "chickpeas" <> monoid') where
    (val', monoid') = (False, "")
= { substitute away val' and monoid' everywhere }
(False, "chickpeas" <> "")
= { evaluate <> }
(False, "chickpeas")
Run Code Online (Sandbox Code Playgroud)