我对liftM如何保存上下文感到困惑,特别是在Writer monad的情况下。我已经读过“学习你一个伟大的好的Haskell”,并且坚持它对liftM的解释。
下面是一个示例:
ghci> runWriter $ liftM not $ Writer (True, "chickpeas")
(False,"chickpeas")我理解这样一个概念,即liftM将not函数提升到monad中,将其应用到内部值(True)中,或者对单子("chickpeas")不做任何操作,或者将其与字符串的标识单子组合("")。
但是,liftM的实现如下:
liftM :: (Monad m) => (a -> b) -> m a -> m b  
liftM f m = m >>= (\x -> return (f x))将f应用于被输入到函数的monad内部的x值是有意义的。但是,如果我执行return (f x),为什么不返回f x生成的在默认的monad上下文中封装的内容呢?在上面的Writer示例中,我希望runWriter $ return (f x)生成(False, ""),因为默认的Writer string bool实例有"“作为它的monoid值。
我遗漏了什么?
发布于 2017-10-10 16:32:22
您非常专注于\x -> return (f x),以至于完全忘记了它之前的m >>=!
对于return所做的事情,您是绝对正确的:
Control.Monad.Writer> return (not True) :: Writer String Bool
WriterT (Identity (False,""))您已经忘记的是绑定,它是这样实现的(直到一些newtype和转换器的废话):
m >>= f = (val', monoid <> monoid') where
    (val, monoid) = m
    (val', monoid') = f val在我们的例子中,这个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")发布于 2017-10-10 16:44:58
关键是>>=用于Writer的定义。以下是简化的,因为Writer是用WriterT Identity定义的
w >>= f = Writer (m <> n, b)
  where (m, a) = runWriter w
        (n, b) = runWriter (f a)现在,如果我们用这个定义来扩展liftM,您就可以看到单线作者值是如何累积起来的。
liftM f w = w >>= \x -> return (f x)
          {- expand definiton of (>>=) -}
          = Writer (m <> n, b)
                where (m, a) = runWriter w
                      (n, b) = runWriter ((\x -> return (f x)) a)
          {- apply (\x -> return (f x)) to its argument -}
          = Writer (m <> n, b)
                where (m, a) = runWriter w
                      (n, b) = runWriter (return (f a))
          {- expand definition of (return (f a)) -}
          = Writer (m <> n, b)
                where (m, a) = runWriter w
                      (n, b) = runWriter (Writer ("", f a))
          {- runWriter . Writer === id -}
          = Writer (m <> n, b)
                where (m, a) = runWriter w
                      (n, b) = ("", f a)
          {- inline 'n' and 'b' -}
          = Writer (m <> "", f a) where (m, a) = runWriter w
          {- "" is the identity element -}
          = Writer (m, f a) where (m, a) = runWriter w从最后一个等式中,您可以看到liftM f (Writer (m, a))将f应用于Writer中的a值,同时保留前一个单子值m。
https://stackoverflow.com/questions/46670949
复制相似问题