Haskell 服务处理程序中的任一计算

Haskell 服务处理程序中的任一计算,haskell,monad-transformers,servant,Haskell,Monad Transformers,Servant,A是例外项上的新类型包装,具有MonadThrow、MonadCatch、MonadError等实例 这可能是一个有点做作的例子,但它显示了我经常面临的一个问题: 在处理程序中,我想调用三个返回字符串Int的函数,然后执行类型Int->Int->Int->IO(SomeError Text)的计算,从前面取三个Int 我应该如何构造此代码以确保尽早返回错误 我发现我可以使用other的Monad实例将前三个other String Int计算“折叠”为例如other String(Int,Int

A是
例外项上的新类型包装,具有
MonadThrow
MonadCatch
MonadError
等实例

这可能是一个有点做作的例子,但它显示了我经常面临的一个问题:

在处理程序中,我想调用三个返回
字符串Int
的函数,然后执行类型
Int->Int->Int->IO(SomeError Text)
的计算,从前面取三个
Int

我应该如何构造此代码以确保尽早返回错误

我发现我可以使用
other
Monad
实例将前三个
other String Int
计算“折叠”为例如
other String(Int,Int,Int)
,然后将
IO
计算绑定到某个结果值,然后使用
case
来决定是返回一个成功的结果,还是使用
throwError
来抛出
SomeError
类型(转换后?),但我希望能够如下所示:

f, g, h :: Either String Int
a :: Int -> Int -> Int -> IO (Either SomeError Text) 

myHandler :: Handler Text
myHandler = do
    x1 <- f
    x2 <- g
    x3 <- h
    liftIO $ convertError $ (a x1 x2 x3)
f,g,h::字符串Int
a::Int->Int->Int->IO(某个错误文本)
myHandler::Handler文本
myHandler=do

x1假设您有一个函数
strotservanterr::String->ServantErr
,用于将
f,g,h
返回的错误转换为处理程序可以返回的错误,那么我们可以使用:

  • 任一字符串Int
    s转换为
    ExceptT字符串
    s
  • 根据
    处理程序的要求,将
    ExceptT字符串
    转换为
    ExceptT ServantErr

现在我们已经对参数进行了排序,我们可以使用相同的想法来修复返回。将您的
convertError
函数重命名为
someErrorToServantErr
,以实现一致性,并假设它具有类型
SomeError->ServantErr
,则我们可以执行以下操作:

result <- liftIO $ a x1 x2 x3
withExceptT someErrorToServantErr $ liftEither result
它将尽快失败,并根据需要转换错误,虽然它很密集,但希望不是那么不可读


您也可以选择应用程序路线,尽管我找不到一种特别好的方法(虽然我很少使用应用程序函子,但我可能缺少一些有用的技巧):

myHandler::Handler文本
myHandler=do
让[x1,x2,x3]=map(liftMapE-strotservanterr)[f,g,h]-[Handler-Int]

tmp您可能有一个问题,即
处理程序
是一个
例外的ServantErr
,但您的错误是
字符串
s。我们可以假设您有一个函数
String->ServantErr
,可以用来转换错误吗?您可以更进一步,在ExceptT monad(或类似的东西)中使用自定义错误类型,并使用
wingserver
(请参阅)。@AlpMestanogullari噢,酷。我并不知道关于仆人的任何事情,所以希望OP能看到你的评论并发现它很有用。
[x1, x2, x3] <- mapM (withExceptT strToServantErr . liftEither) [f, g, h]
result <- liftIO $ a x1 x2 x3
withExceptT someErrorToServantErr $ liftEither result
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
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