将带有 ExceptT 的源传递给接收器
Passing a source with ExceptT to a sink
给定具有以下类型签名的管道源:
sourceMsg :: MonadIO m => ExceptT Err (ConduitM () ByteString m) ()
怎么传给Data.Conduit.List.mapM_
?像下面这样的东西是行不通的,因为输出的类型是 ConduitM a o m ()
,而不是 ConduitM a o m (Either Err ())
。
> :t ($$) (runExceptT $ sourceMsg undefined) (mapM_ undefined)
<interactive>:1:7: Warning:
Couldn't match type ‘Either Err ()’ with ‘()’
Expected type: Source m ByteString
Actual type: ConduitM () ByteString m (Either Err ())
In the first argument of ‘($$)’, namely
‘(runExceptT $ sourceMsg undefined)’
In the expression:
($$) (runExceptT $ sourceMsg undefined) (mapM_ undefined)
我只想在 mapM_
内打印字节串的长度。
让我们假设您的水槽管道段是 C.mapM_ BS.putStrLn
。
第一步是解包 ExceptT 值并将其与接收器段进行比较:
runExceptT sourceMsg :: ConduitM () ByteString IO (Either Err ())
C.mapM_ BS.putStrLn :: ConduitM ByteString a IO ()
当您使用 Conduit 融合运算符时,您必须选择哪个段将 return 融合表达式的值。两个主要选择是:
a =$= b -- b returns the value
a `fuseUpstream` b -- a returns the value
因为我们想看到 Either Err ()
值,我们将使用 fuseUpstream
:
let f = (runExceptT sourceMsg) `fuseUpstream` (C.mapM_ BS.putStrLn)
:: ConduitM () c IO (Either Err ())
(将两个段融合在一起的另一个要求是段 而不是 returning 值必须 return ()
。在我们的如果 C.mapM_ ...
已经满足了,但通常需要检查。通过使用 const ()
)
下一步是 运行 融合片段以产生 IO 操作:
runConduit f :: IO (Either Err ())
现在我们可以判断是否有错误。完整解决方案:
{-# LANGUAGE OverloadedStrings #-}
import Control.Monad.Trans.Except
import Data.Conduit as C
import Data.Conduit.List as C
import qualified Data.ByteString.Char8 as BS
import Data.ByteString (ByteString)
import Control.Monad
type Err = (Int, String)
sourceMsg :: ExceptT Err (ConduitM () ByteString IO) ()
sourceMsg = undefined
runSource = do
do r <- runConduit $ (runExceptT sourceMsg) `fuseUpstream` (C.mapM_ BS.putStrLn)
case r of
Left _ -> putStrLn "error"
Right _ -> putStrLn "no error"
给定具有以下类型签名的管道源:
sourceMsg :: MonadIO m => ExceptT Err (ConduitM () ByteString m) ()
怎么传给Data.Conduit.List.mapM_
?像下面这样的东西是行不通的,因为输出的类型是 ConduitM a o m ()
,而不是 ConduitM a o m (Either Err ())
。
> :t ($$) (runExceptT $ sourceMsg undefined) (mapM_ undefined)
<interactive>:1:7: Warning:
Couldn't match type ‘Either Err ()’ with ‘()’
Expected type: Source m ByteString
Actual type: ConduitM () ByteString m (Either Err ())
In the first argument of ‘($$)’, namely
‘(runExceptT $ sourceMsg undefined)’
In the expression:
($$) (runExceptT $ sourceMsg undefined) (mapM_ undefined)
我只想在 mapM_
内打印字节串的长度。
让我们假设您的水槽管道段是 C.mapM_ BS.putStrLn
。
第一步是解包 ExceptT 值并将其与接收器段进行比较:
runExceptT sourceMsg :: ConduitM () ByteString IO (Either Err ())
C.mapM_ BS.putStrLn :: ConduitM ByteString a IO ()
当您使用 Conduit 融合运算符时,您必须选择哪个段将 return 融合表达式的值。两个主要选择是:
a =$= b -- b returns the value
a `fuseUpstream` b -- a returns the value
因为我们想看到 Either Err ()
值,我们将使用 fuseUpstream
:
let f = (runExceptT sourceMsg) `fuseUpstream` (C.mapM_ BS.putStrLn)
:: ConduitM () c IO (Either Err ())
(将两个段融合在一起的另一个要求是段 而不是 returning 值必须 return ()
。在我们的如果 C.mapM_ ...
已经满足了,但通常需要检查。通过使用 const ()
)
下一步是 运行 融合片段以产生 IO 操作:
runConduit f :: IO (Either Err ())
现在我们可以判断是否有错误。完整解决方案:
{-# LANGUAGE OverloadedStrings #-}
import Control.Monad.Trans.Except
import Data.Conduit as C
import Data.Conduit.List as C
import qualified Data.ByteString.Char8 as BS
import Data.ByteString (ByteString)
import Control.Monad
type Err = (Int, String)
sourceMsg :: ExceptT Err (ConduitM () ByteString IO) ()
sourceMsg = undefined
runSource = do
do r <- runConduit $ (runExceptT sourceMsg) `fuseUpstream` (C.mapM_ BS.putStrLn)
case r of
Left _ -> putStrLn "error"
Right _ -> putStrLn "no error"