bet*_*eta 6 haskell monad-transformers servant
仆人服务器处理程序是 , 的新类型包装器ExceptT
,并且具有MonadThrow
, MonadCatch
,MonadError
等的实例。
这可能是一个有点人为的例子,但它显示了我经常面临的一个问题:
\n\n在处理程序中,我想调用三个返回的函数Either String Int
,然后执行类型的计算,获取之前的Int -> Int -> Int -> IO (Either SomeError Text)
三个s 。Int
我应该如何构造这段代码以确保尽早返回错误?
\n\n我看到我可以使用Either
\'sMonad
实例将 \xe2\x80\x9ccollapse\xe2\x80\x9d 的前三个Either String Int
计算放入 eg 中Either String (Int,Int,Int)
,然后将IO
计算绑定到某个结果值,然后用于case
决定是否返回成功结果或用于throwError
抛出SomeError
类型(转换后?),但我希望能够执行以下操作:
f, g, h :: Either String Int\na :: Int -> Int -> Int -> IO (Either SomeError Text) \n\nmyHandler :: Handler Text\nmyHandler = do\n x1 <- f\n x2 <- g\n x3 <- h\n liftIO $ convertError $ (a x1 x2 x3)\n
Run Code Online (Sandbox Code Playgroud)\n\n是否可以像上面的代码那样写?
\n假设您有一个函数strToServantErr :: String -> ServantErr
可以将返回的错误转换f,g,h
为处理程序可以返回的错误,那么我们可以使用:
liftEither
将Either String Int
s 变成ExceptT String
s。withExceptT
根据 的要求从 转换ExceptT String
为。ExceptT ServantErr
Handler
x1 <- withExceptT strToServantErr $ liftEither f
Run Code Online (Sandbox Code Playgroud)
当您执行此操作三次时,我们可以使用以下命令使其更简洁mapM
:
[x1, x2, x3] <- mapM (withExceptT strToServantErr . liftEither) [f, g, h]
Run Code Online (Sandbox Code Playgroud)
现在我们已经对参数进行了排序,我们可以使用相同的想法来修复返回。将您的convertError
函数重命名为以someErrorToServantErr
保持一致性并假设它具有 type SomeError -> ServantErr
,那么我们可以这样做:
result <- liftIO $ a x1 x2 x3
withExceptT someErrorToServantErr $ liftEither result
Run Code Online (Sandbox Code Playgroud)
我们解开IO
的计算a
,然后将其提升为ExceptT
并转换异常类型。
将一些代码整理到辅助函数中后,我们得到如下内容:
myHandler :: Handler Text
myHandler = do
[x1, x2, x3] <- mapM (liftMapE strToServantErr) [f, g, h]
eitherResult <- liftIO $ a x1 x2 x3
liftMapE someErrorToServantErr eitherResult
where liftMapE f = withExceptT f . liftEither
Run Code Online (Sandbox Code Playgroud)
这将尽快失败,并根据需要转换错误,虽然它很密集,但希望不是那么不可读。
你也可以走Applicative路线,尽管我找不到一种让它特别好的方法(虽然我没有太多使用applicative函子,但我可能错过了一些有用的技巧):
myHandler :: Handler Text
myHandler = do
let [x1, x2, x3] = map (liftMapE strToServantErr) [f, g, h] -- [Handler Int]
tmp <- a <$> x1 <*> x2 <*> x3 -- IO (Either SomeError Text)
eitherResult <- liftIO $ tmp
liftMapE someErrorToServantErr eitherResult
where liftMapE f = withExceptT f . liftEither
Run Code Online (Sandbox Code Playgroud)
欢迎对上述代码进行任何改进!