我想在servant 0.5中构建一个简单的rest api示例:
data MyData = MyData { var1 :: Int, var2 :: String }
app :: Application
app = serve api server
api :: Proxy API
api = Proxy
server :: Server API
server = getItems
getItems :: EitherT ServantErr IO [MyData]
getItems = runEitherT $ do
aa <- nextRandom -- IO
bb <- getCurrentTime -- IO
cc <- getDataFromDb -- IO
--noteT ??? How???
--MaybeT ??? How???
return $ Just [MyData 111 222]
startApp :: IO ()
startApp = run 8080 app
我无法编译,因为很多错误&#34;无法匹配预期类型&#34;在不同的地方。我猜是因为我在&#34; getItems&#34;中混合了2个不同的monad。但不仅如此。
答案 0 :(得分:4)
下面:
getItems :: ExceptT ServantErr IO [MyData]
getItems = runExceptT $ do
ExceptT ServantErr IO [MyData]
从IO (Either ServantErr [MyData]
到ExceptT
的作用是什么。它消除了IO a
newtype。但你想走另一条路!
您可以使用runExceptT
将任何ExceptT ServantErr IO a
操作解除为ExceptT
操作。它基本上告诉IO
包装器&#34;只需将IO
操作的结果放在成功上下文&#34;。
由于你的整个do-block似乎都存在getItems :: ExceptT ServantErr IO [MyData]
getItems = liftIO $ do
aa <- nextRandom -- IO
bb <- getCurrentTime -- IO
cc <- getDataFromDb -- IO
...
,你可以写:
IO
而不是单独解除每个Either
行动。
其他常见情况:
如果您使用纯ExceptT
,请使用liftIO
将其提升为Maybe
。
如果您有纯IO (Maybe a)
,请使用hoistEither :: Monad m => Either e a -> ExceptT e m a
并提供错误。
如果您有IO (Either e a)
,请使用failWith :: Applicative m => e -> Maybe a -> ExceptT e m a
并提供错误。
如果您有ExceptT
,请将其包装在ExceptT
构造函数中。
要更改docker run hello-world
所携带的错误类型,请使用failWithM :: Applicative m => e -> m (Maybe a) -> ExceptT e m a
。
所有这些功能都非常简单,查看它们的源代码是有益的。