一个简单的例子rest api in servant or "how to mix monads properly"?

A simple example of rest api in servant or "how to mix monads properly"?

我想在 servant 0.5 中构建一个休息 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  

由于"Couldn't match expected type"在不同地方有很多错误,我无法编译它。我想这是因为我在 "getItems" 中混合了 2 个不同的单子。但不仅如此。

此处:

getItems :: ExceptT ServantErr IO [MyData]
getItems = runExceptT $ do

runExceptT 所做的是从 ExceptT ServantErr IO [MyData]IO (Either ServantErr [MyData]。它消除了 ExceptT 新类型。但是你想走另一条路!

您可以使用 liftIO 将任何 IO a 动作提升为 ExceptT ServantErr IO a 动作。它基本上告诉 ExceptT 包装器 "just put the result of the IO action in a success context".

因为你的整个 do-block 似乎都在 IO 中,你可以只写:

getItems :: ExceptT ServantErr IO [MyData]
getItems = liftIO $ do
    aa <- nextRandom -- IO
    bb <- getCurrentTime -- IO
    cc <- getDataFromDb -- IO
    ...

而不是单独提升每个 IO 动作。

其他常见情况:

所有这些函数都非常简单,查看它们的源代码很有启发性。