3

カスタムモナドスタックで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 }

さて、多くのハンドラーでは、db からいくつかのデータ (Persistent) をフェッチしてそれに基づいて処理する必要があるだけなので、次のようになります。

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ヘルパーとの発見に至りました。だから私は次のようにしてみました:

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

しかし、これはコンパイルされません。!?ここの結果は次のExceptT ServantErr m0 (Entity SomeEntity)とおりAppHandler (Entity SomeEntity)です。そのような値をハンドラーの型に戻すにはどうすればよいですか?

4

2 に答える 2

3

(!?)返されるモナドで多態的であるバリアントが必要です。例えば:

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

次に、提供されerr400 :: ServantErrorた--これはあなたが宣言したエラーのタイプですAppHandler-あなたは書くことができます

runDb (getCompanyByName companyName) !?? err400
于 2016-05-29T23:13:09.747 に答える