I have the following pattern of a Reader with a Semigroup Element:
runFunction :: Reader Env Element
runFunction = do
a <- getA
b <- getB
c <- getC
return $ a <> b <> c
Where getA :: Reader Env Element
.
Is there a way to:
runFunction = do
getA
getB
getC
I feel like I see this pattern alot, where I imperatively chain monadic calls, and they get turned into a single element at the end.
Note: I don't want to do getA >>= getB >>= getC
since getB
isn't :: Element -> Reader Env Element
It feels like a State Monad, that automatically modifies state with <>
, but I don't know.
Working with monadic code is still quite fresh to me.
The WriterT
monad transformer can be used to build up a monoidal value with each action.
You can use lift
to wrap your Reader
actions into the WriterT
monad transformer, then move the result of each action into the monad's environment by using tell
, sequence the actions, and then unwrap the result back to a single Reader
action using execWriterT
.
Here is what I mean:
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
As you can see, this generalizes to any monad, not just Reader
.