Best way to combine multiple state/reader monads?

Viewed 135

I am writing a project that involves composing several stacks of StateT and ReaderT monads:

newtype FooT m a = FooT { unFooT :: (StateT State1 (ReaderT Reader1 m)) a }

newtype BarT m a = BarT { unBarT :: (StateT State2 (ReaderT Reader2 m)) a }

Then, I basically just run everything in FooT (BarT m) and lift into the appropriate monad as necessary. I'm using lens to interact with the various state/reader types:

foo :: Monad m => FooT m ()
foo = do
  field1 .= ... -- where field1 is a lens into State1
  ...

However, this approach gets ugly as I add more StateT + ReaderT transformers (and seems like it might incur some performance costs).

My only idea so far is to combine the states like:

newtype BazT m a = BazT { unBazT :: StateT (State1, State2) (ReaderT (Reader1, Reader2) m)) a }

and then I can just project into the state types with more lenses.

foo :: Monad m => BazT m ()
foo = do
  (_1 . field1) .= ... -- where field1 is a lens into State1
  ...

Is there a canonical way to combine multiple states like this? If possible I'd like to avoid modifying all the lens code.

0 Answers
Related