有Monad可以收集结果并将其“附加”吗?

问题描述

我具有带有半群元素的阅读器以下模式:

runFunction :: Reader Env Element
runFunction = do
  a <- getA
  b <- getB
  c <- getC
  return $ a <> b <> c

getA :: Reader Env Element处。

有没有办法:

runFunction = do
  getA
  getB
  getC

我觉得我看到了很多这种模式,在这些命令中,我强制性地链接单子调用,它们最终变成一个元素。

注意:我不想做getA >>= getB >>= getC,因为getB不是:: Element -> Reader Env Element

感觉就像是State Monad,它会自动<>修改状态,但我不知道。

对我来说,使用单子代码仍然很新鲜。

解决方法

WriterT monad变换器可用于在每个动作中建立一个单调值。

您可以使用liftReader动作包装到WriterT monad转换器中,然后通过使用tell将序列的每个动作的结果移动到monad的环境中操作,然后使用execWriterT将结果解开为单个Reader操作。

这是我的意思:

import Control.Monad.Writer

wrap :: (Monad m,Monoid w) => m w -> WriterT w m ()
wrap m = lift m >>= tell

unwrap :: (Monad m) => WriterT w m a -> m w
unwrap = execWriterT

runFunction :: Reader Env Element
runFunction = unwrap $ do
    wrap getA
    wrap getB
    wrap getC

如您所见,这可以推广到任何monad,而不仅仅是Reader

,
runFunction = fmap mconcat . sequence $ [getA,getB,getC]

单子是什么。

fmap mconcat . sequence
  :: (Monoid b,Monad f,Traversable t) => t (f b) -> f b

列表[]是可遍历的。

对于Semigroups,有sconcat