我对liftM
如何保留上下文感到困惑,特别是在Writer
monad的情况下。我一直在经历“让你学习哈斯克尔以获得伟大的利益”,并坚持对liftM
的解释。
以下是一个例子:
ghci> runWriter $ liftM not $ Writer (True, "chickpeas")
(False,"chickpeas")
我理解liftM
将not
函数提升到monad中的概念,将其应用于内部的值(True
),并且对monoid(“鹰嘴豆”)不执行任何操作)或将其与字符串(“”)的身份monoid组合。
但是,liftM
的实施方式如下:
liftM :: (Monad m) => (a -> b) -> m a -> m b
liftM f m = m >>= (\x -> return (f x))
将f
应用于正在输入函数的monad中的x
值是有意义的。但是,如果我执行return (f x)
,为什么我不能找回在默认 monad上下文中包含的f x
生成内容?在上面的Writer
示例中,我希望runWriter $ return (f x)
生成(False, "")
,因为默认的Writer string bool
实例具有“”作为其monoid值。
我错过了什么?
答案 0 :(得分:5)
你已经非常专注于\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")
答案 1 :(得分:3)
关键是>>=
Writer
的定义。以下内容已经过简化,因为Writer
是根据WriterT Identity
:
w >>= f = Writer (m <> n, b)
where (m, a) = runWriter w
(n, b) = runWriter (f a)
现在,如果我们使用liftM
的此定义展开>>=
,您可以看到如何累积monoidal writer-value。
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
应用于a
内的Writer
值,同时保留之前的幺半群值{{1} }。