我正在尝试实现一个简单的Web服务器,该服务器与其他一些API交互并在进行一些处理后存储响应。
为了封装失败的可能性(空响应、不正确的请求等(,我使用以下ExceptT
:
getExample
:: (MonadIO m, MonadReader ApplicationConfig m)
=> ExceptT ApplicationError m [Example]
getExample = do
partOfReq <- asks requestForSometing
fn1 =<< fn2 partOfReq
我还有另一个函数,它使用 Persistent 的insertMany_将响应存储在数据库中。
storeExample
:: ( MonadIO m
, PersistStoreWrite backend
, PersistEntityBackend Example ~ BaseBackend backend
)
=> [Example]
-> ReaderT backend m ()
storeExample = insertMany_
现在我想写一个函数
getResponseAndStore = ... {- A combination of getExample and storeExample -}
这将做这两件事,并将ApplicationConfig
和PersistEntityBackend
需求提升到顶部,用户可以捆绑提供它们。
这可能吗?
如果是这样 - 战略/实施是什么?
如果没有 - 我应该考虑哪些更改?
编辑:这是我目前正在做的事情。
getResponseAndStore
:: ( MonadIO m
, MonadReader ApplicationConfig m
, PersistStoreWrite backend
, PersistEntityBackend Example ~ BaseBackend backend
)
=> ReaderT backend (ExceptT ApplicationError m) ()
getResponseAndStore = storeExample =<< lift getExample
我能够制作一个只想要我想要的函数。秘诀是使用PostgresqlConn。
process :: ReaderT ApplicationConfig IO (Either ApplicationError ())
process = do
appConfig <- ask
connStr <- asks connectionString
runStdoutLoggingT
$ withPostgresqlConn connStr
$ flip ($) appConfig
. runReaderT
. runExceptT
. runReaderT getResponseAndStore
你不能改用MonadError
语法吗?
getExample
:: (MonadIO m, MonadReader ApplicationConfig m, MonadError ApplicationError m)
=> [Example]
getExample = -- ...
getResponseAndStore :: (MonadIO m, MonadReader ApplicationConfig m, PersistStoreWrite backend, PersistEntityBackend Example ~ BaseBackend backend, MonadError ApplicationError m) => -- etc.