2016-06-18 5 views
1

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の場合は、パイプラインから抜け出すのはいいだろう、とトップにエラーメッセージを返します。 私はこれをblog postと読んでいますが、コンジット(これも複雑な型名を持っています)にそれを適用するには十分に理解していません。私は導管に提案されたアプローチhereを適用したいと思っています - それはEitherTのアプローチで提案されているようです今ExceptTによって包含されています。

答えて

1

覚えて便利なシグネチャは次のとおりです。

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が提供する エラーチェックコードがトリガーされます。したがって、inpLeftの場合、 のエラーが発生します。ここで

更新

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() 
+0

ありがとうございました。私はexceptTをよく知っていますが、 'ExceptT Err(Consumer ByteString m())()'のようなシグネチャをどうやって取得するかはまだ分かりません。パイプラインレベルの上でエラー処理をしようとしているので、どちらかに行くのが良いかどうかは分かりません。このようなものは、 '' $$ 'のようなものです。停止して「左」エラーを返します。パイプの場合は、私の質問にリンクされているポストに書かれているように、それはExceptT e(Pipe a b m)rです。 – Sal

+0

「Sink」で更新された回答。実際には、コンシューマがその型パラメータの1つで普遍的に修飾されているため、 'ExceptT Err(Consumer ...) 'を作成することはできません。 'パイプ'はそれほど定義されていません - 'シンク'に近いです。だから私は 'ExceptT ...シンク...'あなたが探しているものだと思います – ErikR

+0

まあ、私は同じように思った。助けてくれてありがとう。 – Sal

関連する問題