在 ExceptT 中包装管道
Wrapping conduit in ExceptT
在 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
的情况下,打破管道会很好,并且return错误信息到顶部。
我阅读此 blog post but haven't understood it well enough yet to apply it to conduit (which also has complicated type signature). I will like to apply the proposed approach here 以引导 - 该方法中建议的 EitherT
似乎已被 ExceptT
包含。
要记住的一个有用的签名是:
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
构造函数。
然后,当您对 ExceptT ...
值调用绑定时,您会触发
ExceptT 提供的错误检查代码。因此,如果 inp
是一个 Left
将引发错误。
更新
这里是 Sink
的版本:
sink' :: MonadIO m => ExceptT Err (Sink ByteString m) ()
sink' = do bs <- lift await
case bs of
Just inp -> do
msg <- ExceptT (return $ process inp)
liftIO $ BS.putStrLn msg
sink'
Nothing -> return ()
在 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
的情况下,打破管道会很好,并且return错误信息到顶部。
我阅读此 blog post but haven't understood it well enough yet to apply it to conduit (which also has complicated type signature). I will like to apply the proposed approach here 以引导 - 该方法中建议的 EitherT
似乎已被 ExceptT
包含。
要记住的一个有用的签名是:
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
构造函数。
然后,当您对 ExceptT ...
值调用绑定时,您会触发
ExceptT 提供的错误检查代码。因此,如果 inp
是一个 Left
将引发错误。
更新
这里是 Sink
的版本:
sink' :: MonadIO m => ExceptT Err (Sink ByteString m) ()
sink' = do bs <- lift await
case bs of
Just inp -> do
msg <- ExceptT (return $ process inp)
liftIO $ BS.putStrLn msg
sink'
Nothing -> return ()