Created
          March 24, 2012 22:58 
        
      - 
      
 - 
        
Save sjoerdvisscher/2188862 to your computer and use it in GitHub Desktop.  
    Bijection between Twan van Laarhoven's Pipe and the data types from Conduit 
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | -- http://www.reddit.com/r/haskell/comments/rbgvz/conduits_vs_pipes_using_void_as_an_input_or/ | |
| import Control.Monad | |
| import Data.Void | |
| data Pipe m i o r = | |
| NeedInput (i -> Pipe m i o r) (Pipe m Void o r) | |
| | HaveOutput (Pipe m i o r) (m r) o | |
| | Finished (Maybe i) r | |
| | PipeM (m (Pipe m i o r)) (m r) | |
| close :: Monad m => Pipe m i o r -> m r | |
| close (NeedInput _ a) = close a | |
| close (HaveOutput _ a _) = a | |
| close (Finished _ a) = return a | |
| close (PipeM _ a) = a | |
| convert :: Monad m => Pipe m i o r -> Pipe m Void o r | |
| convert (NeedInput _ pipe) = pipe | |
| convert (HaveOutput pipe mr o) = HaveOutput (convert pipe) mr o | |
| convert (Finished _ r) = Finished Nothing r | |
| convert (PipeM mc mr) = PipeM (liftM convert mc) mr | |
| instance Monad m => Monad (Pipe m i o) where | |
| return = Finished Nothing | |
| m >>= f = case m of | |
| Finished _ r -> f r | |
| PipeM mc mr -> PipeM (liftM (>>= f) mc) (mr >>= close . f) | |
| NeedInput fc pipe -> NeedInput ((>>= f) . fc) (pipe >>= convert . f) | |
| HaveOutput pipe mr o -> HaveOutput (pipe >>= f) (mr >>= close . f) o | |
| {----------------------------------------------------------------------------- | |
| Sink | |
| ------------------------------------------------------------------------------} | |
| data Sink i m o = | |
| Processing (i -> Sink i m o) (SinkClose m o) | |
| | Done (Maybe i) o | |
| | SinkM (m (Sink i m o)) | |
| type SinkClose m o = m o | |
| toSink :: Monad m => Pipe m i Void r -> Sink i m r | |
| toSink (NeedInput a b) = Processing (toSink . a) (close b) | |
| toSink (HaveOutput _ _ v) = absurd v | |
| toSink (Finished a b) = Done a b | |
| toSink (PipeM a _) = SinkM (toSink `liftM` a) | |
| fromSink :: Monad m => Sink i m r -> Pipe m i Void r | |
| fromSink (Processing a b) = NeedInput (fromSink . a) (PipeM (Finished Nothing `liftM` b) b) | |
| fromSink (Done a b) = Finished a b | |
| fromSink (SinkM a) = PipeM (fromSink `liftM` a) (close . fromSink =<< a) | |
| {----------------------------------------------------------------------------- | |
| Conduit | |
| ------------------------------------------------------------------------------} | |
| data Conduit i m o = | |
| NeedInput' (i -> Conduit i m o) (ConduitClose m o) | |
| | HaveOutput' (Conduit i m o) (m ()) o | |
| | Finished' (Maybe i) | |
| | ConduitM (m (Conduit i m o)) (m ()) | |
| type ConduitClose m o = Source m o | |
| toConduit :: Monad m => Pipe m i o () -> Conduit i m o | |
| toConduit (NeedInput a b) = NeedInput' (toConduit . a) (toSource b) | |
| toConduit (HaveOutput a b c) = HaveOutput' (toConduit a) b c | |
| toConduit (Finished a ()) = Finished' a | |
| toConduit (PipeM a b) = ConduitM (toConduit `liftM` a) b | |
| fromConduit :: Monad m => Conduit i m o -> Pipe m i o () | |
| fromConduit (NeedInput' a b) = NeedInput (fromConduit . a) (fromSource b) | |
| fromConduit (HaveOutput' a b c) = HaveOutput (fromConduit a) b c | |
| fromConduit (Finished' a) = Finished a () | |
| fromConduit (ConduitM a b) = PipeM (fromConduit `liftM` a) b | |
| {----------------------------------------------------------------------------- | |
| Source | |
| ------------------------------------------------------------------------------} | |
| data Source m a = | |
| Open (Source m a) (m ()) a | |
| | Closed | |
| | SourceM (m (Source m a)) (m ()) | |
| toSource :: Monad m => Pipe m Void a () -> Source m a | |
| toSource (NeedInput _ a) = toSource a | |
| toSource (HaveOutput a b c) = Open (toSource a) b c | |
| toSource (Finished _ _) = Closed | |
| toSource (PipeM a b) = SourceM (toSource `liftM` a) b | |
| fromSource :: Monad m => Source m a -> Pipe m Void a () | |
| fromSource (Open a b c) = HaveOutput (fromSource a) b c | |
| fromSource Closed = Finished Nothing () | |
| fromSource (SourceM a b) = PipeM (fromSource `liftM` a) b | 
I think using close is exactly right, because closing is what m r is for. I added your instance to the code.
With that I was able to figure out the Applicative instance after the fashion of Control.Pipe.Common and a few other things. The 'Category' instance went through without much difficulty at all, though I left it and MonadTrans implicit. https://gist.github.com/2203876
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment
  
            
The
Functorinstance forPipe i o m ris easy with these constructors, but I came to grief withMonadandApplicative, but maybe it's that I don't have enough of the needed intuition to know what to throw out. For example, the switch fromm ()as the second constructor inCondiutMandSinkMtom rinPipeMmeans that the function in=<< fneeds to be used twice, so that you end up with twom (Pipe i o m r)s and don't know what to do with them. In Conduit you can just carry them over.