Передача источника с ExceptT в приемник


person Sal    schedule 18.06.2016    source источник


Ответы (1)


Предположим, что ваш сегмент кабелепровода раковины — C.mapM_ BS.putStrLn.

Первый шаг — развернуть значение ExceptT и сравнить его с сегментом приемника:

runExceptT sourceMsg :: ConduitM () ByteString IO (Either Err ())
C.mapM_ BS.putStrLn  :: ConduitM ByteString a  IO ()

Когда вы используете операторы объединения Conduit, вы должны выбрать, какой сегмент будет возвращать значение объединенного выражения. Два основных варианта:

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

(Еще одно требование для объединения двух сегментов состоит в том, что сегмент, не возвращающий значение, должен возвращать (). В нашем случае это уже удовлетворяет C.mapM_ ..., но в целом это нужно проверить. Сегмент всегда может быть изменен, чтобы возвращать (), сопоставляя его с const ())

Следующим шагом является запуск объединенных сегментов для получения действия ввода-вывода:

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"
person ErikR    schedule 18.06.2016
comment
Большое спасибо, @ErickR. Очень полезно. - person Sal; 18.06.2016