在ExceptT
中换行管道的好方法是什么?该方法应在出现错误时停止处理,并提取错误消息。这是一个没有错误处理的玩具代码 - 它只是默默地停止:
import Data.Conduit as C
import Data.ByteString as BS
import Control.Monad
import Control.Monad.IO.Class
import Data.Text as T
-- just a dummy processing to simulate errors
process :: BS.ByteString -> Either (Int,T.Text) BS.ByteString
process inp = if (BS.null inp) then Left $ (1,"Empty input") else Right inp
-- silent processing - stops on error but doesn't tell us what it is
sink :: MonadIO m => Consumer BS.ByteString m ()
sink = do
bs <- await
case bs of
Just val -> do
let msg = process val
case msg of
Left _ -> return ()
Right x -> (liftIO $ return x) >> sink
Nothing -> return ()
我们怎样才能将sink
的类型签名更改为下面的内容?
sink :: MonadIO m => ExceptT e m (Consumer BS.ByteString m ())
如果是Left
,最好突破管道,并将错误消息返回到顶部。
我读过这个blog post但是还没有完全理解它还没有应用到管道(它也有复杂的类型签名)。我想将建议的方法here应用于管道 - 似乎EitherT
在方法中建议现在已归入ExceptT
。
答案 0 :(得分:1)
要记住的有用签名是:
options
并考虑到这一点,此代码类型检查:
ExceptT :: m (Either e b) -> ExceptT e m b
这不是一个简单的接收器,但它应该说明如何做事。
在线(***)的输入如下:
{-# LANGUAGE OverloadedStrings #-}
import Control.Monad.Trans.Class
import Control.Monad.Trans.Except
import Data.Conduit as C
import Data.ByteString.Char8 as BS
import Control.Monad
import Control.Monad.IO.Class
import Data.Text as T
-- just a dummy processing to simulate errors
process :: BS.ByteString -> Either (Int,T.Text) BS.ByteString
process inp = if (BS.null inp) then Left $ (1,"Empty input") else Right inp
type Err = (Int,T.Text)
sink' :: MonadIO m => ExceptT Err (ConduitM ByteString Int m) ()
sink' = do bs <- lift await
case bs of
Just inp -> do
msg <- ExceptT (return $ process inp) -- ***
lift $ yield (BS.length msg)
liftIO $ BS.putStrLn msg
sink'
Nothing -> return ()
所以在这里使用process inp :: Either Err ByteString
-- (a pure value)
return (process inp) :: m (Either Err ByteString)
-- here m = ConduitM ByteString Int mIO
ExceptT (...) :: ExceptT Err m ()
进行设置,以便我们可以应用return
构造函数。
然后当您在ExceptT
值上调用bind时,会触发
错误检查ExceptT提供的代码。因此,如果ExceptT ...
是inp
个
错误将被提出。
<强>更新强>
以下是Left
的版本:
Sink