haskell - 将 failWith 与 Servant 和自定义 monad 堆栈一起使用

标签 haskell monad-transformers servant

我正在使用带有自定义 monad 堆栈的 Servant:

newtype AppHandler a = AppHandler { runHandler :: ReaderT Config (ExceptT ServantErr IO) a }
  deriving (Functor, Applicative, Monad, MonadReader Config, MonadError ServantErr, MonadIO)

data Config = Config
    { getPool :: ConnectionPool }

现在,在许多处理程序中,我只需要从数据库中获取一些数据(持久性)并对其进行操作,所以我得到了:

runDb :: (MonadReader Config m, MonadIO m) => SqlPersistT IO b -> m b
runDb query = do
  pool <- asks getPool
  liftIO $ runSqlPool query pool

事实证明,当从 db 中获取数据时,您必然会使用 Maybe,并且通常当 Maybe 为 Nothing 时,您只想抛出错误以便 Servant 服务器将其转换为正确的 HTTP 响应。这让我发现了 Control.Error.Util(!?)::Applicative m => m (Maybe a) -> e -> ExceptT e m a helper 。所以我尝试了以下操作:

someHandler :: AppHandler NoContent
someHandler = do
  entity <- (runDb $ getCompanyByName companyName) !? err400
  -- some more logic
  return NoContent

但这不会编译,!? 的结果是 ExceptT ServantErr m0 (Entity SomeEntity) 但我不再使用这种处理程序类型,它需要AppHandler(实体 SomeEntity)。我如何将此类值转换回我的处理程序类型?

最佳答案

你想要一个 (!?) 的变体,它在返回 monad 时是多态的。例如:

(!??) :: MonadError e m => m (Maybe a) -> e -> m a
act !?? err = act >>= maybe (throwError err) return

然后,提供 err400::ServantError —— 这是你声明 AppHandler 的错误类型 —— 你将能够编写

runDb (getCompanyByName companyName) !?? err400

关于haskell - 将 failWith 与 Servant 和自定义 monad 堆栈一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37515246/

相关文章:

haskell - Haskell 中的不可变变量是什么意思?

haskell - Monad 与 Monad 变压器

haskell - 拥有一个惰性/严格版本的 Writer 有什么意义?

f# - FSharpPlus : the fsi blocks when I try to combine two transformers

haskell - 从servant-0.4.4.7迁移到servant-0.7.1

java - 什么是 VM,为什么动态语言需要 VM?

haskell - 简单的 `foldM` 示例

haskell - 将视频分解为图像进行处理

haskell - 仆人中缺少 CORS header ‘Access-Control-Allow-Origin’

authentication - 使用 RIO 在 Servant.Auth 中拒绝身份验证