haskellmonad-transformershaskell-persistent

What is the strategy for working with different types of Monad Transformers?


I'm trying to implement a simple web server that interacts with some other API and stores the response after doing some processing.

To encapsulate the possibility of failure (empty response, incorrect request, etc) I am using ExceptT as following:

getExample
  :: (MonadIO m, MonadReader ApplicationConfig m)
  => ExceptT ApplicationError m [Example]
getExample = do

  partOfReq <- asks requestForSometing

  fn1 =<< fn2 partOfReq

and I have another function that stores the response in a database using insertMany_ from Persistent.

storeExample
  :: ( MonadIO m
     , PersistStoreWrite backend
     , PersistEntityBackend Example ~ BaseBackend backend
     )
  => [Example]
  -> ReaderT backend m ()
storeExample = insertMany_

Now I want to write a function

getResponseAndStore = ... {- A combination of getExample and storeExample -}

that will do both of these things and bubble up ApplicationConfig and PersistEntityBackend requirements to the top where the user could provide them in a bundle.

Would that be possible?

If so - What would the strategy/implementation be?

If no - What changes shall I consider?

Edit: This is what I'm doing currently.

getResponseAndStore
  :: ( MonadIO m
     , MonadReader ApplicationConfig m
     , PersistStoreWrite backend
     , PersistEntityBackend Example ~ BaseBackend backend
     )
  => ReaderT backend (ExceptT ApplicationError m) ()
getResponseAndStore = storeExample =<< lift getExample

Solution

  • I was able to make a function that does just want I want to. The secret sauce was using withPostgresqlConn.

    process :: ReaderT ApplicationConfig IO (Either ApplicationError ())
    process = do
    
      appConfig <- ask
      connStr   <- asks connectionString
    
      runStdoutLoggingT
        $ withPostgresqlConn connStr
        $ flip ($) appConfig
        . runReaderT
        . runExceptT
        . runReaderT getResponseAndStore