<div dir="ltr">Can I transform a conduit so some values are passed through unchanged, but others go through the conduit? For example:<br><div><div><br> right :: Conduit i m o -> Conduit (Either x i) m (Either x o)<br>
<br></div><div>This is named after the Control.Arrow combinator of the same name:<br><br> right :: ArrowChoice a => a b c -> a (Either d b) (Either d c)<br></div><div><br></div><div>Here's my use case (simplified): I want to compress data with zlib-conduit, which provides:<br>
<br></div><div> compress :: Conduit (Flush ByteString) m (Flush ByteString)<br><br></div><div>The <a href="http://hackage.haskell.org/packages/archive/conduit/latest/doc/html/Data-Conduit.html#t:Flush">Flush</a> wrapper lets me flush the compressor so it will yield cached data right away (though hurting compression a little).<br>
<br></div><div>But before compressing the data, I want to encode it, using this conduit:<br><br></div><div> encode :: Conduit Entry m ByteString<br><br></div><div>I want to combine these, so that if I send a 'Flush', it bypasses 'encode' and feeds to 'compress':<br>
<br></div><div> compressEncode :: Conduit (Flush Entry) m (Flush ByteString)<br><br></div><div>Thus, I need a variant of 'encode' that passes 'Flush' along:<br></div><div><br> encode' :: Conduit (Flush Entry) m (Flush ByteString)<br>
<br></div><div>In my actual program, I don't use Flush, so providing a Conduit combinator just for Flush would not help me.<br><br></div><div>Is something like 'right' possible to implement with Conduit's public API? Here's an implementation using Data.Conduit.Internal (untested):<br>
<br> import Control.Monad (liftM)<br> import Data.Conduit.Internal (Pipe(..), ConduitM(..), Conduit)<br><br> right :: Monad m => Conduit i m o -> Conduit (Either x i) m (Either x o)<br> right = ConduitM . rightPipe . unConduitM<br>
<br> rightPipe :: Monad m<br> => Pipe i i o () m ()<br> -> Pipe (Either x i) (Either x i) (Either x o) () m ()<br> rightPipe p0 = case p0 of<br> HaveOutput p c o -> HaveOutput (rightPipe p) c (Right o)<br>
NeedInput p c -> NeedInput p' (rightPipe . c)<br> where p' (Left x) = HaveOutput (rightPipe p0) (return ()) (Left x)<br> p' (Right i) = rightPipe $ p i<br> Done r -> Done r<br>
PipeM mp -> PipeM $ liftM rightPipe mp<br> Leftover p i -> Leftover (rightPipe p) (Right i)<br><br></div><div>I'm wondering if we could have a Data.Conduit.Arrow module, which provides a newtype variant of Conduit that implements Arrow, ArrowChoice, etc.:<br>
<br></div><div> import qualified Data.Conduit as C<br><br></div><div> newtype Conduit m i o = Conduit (C.Conduit i m o)<br><br></div><div> -- May need Monad constraints for these<br></div><div> instance Category (Conduit m)<br>
</div><div> instance Arrow (Conduit m)<br></div><div> instance ArrowChoice (Conduit m)<br><br></div><div>Does 'Conduit' follow Category, Monad, MonadTrans laws* these days? I'm not talking about Pipe in general, just the special case of it represented by the 'Conduit' type alias:<br>
<br></div><div> Conduit i m o = ConduitM i o m () = Pipe i i o () m ()<br><br></div><div>Or are there some thorny issues (e.g. leftovers) that make following these laws impossible in some cases?<br></div><div><br></div>
<div>Thanks for the input,<br></div><div>-Joey<br></div><div><br> * Assume functions that use Data.Conduit.Internal do so correctly.<br></div></div></div>