2014-07-09 15 views
8

मैं चाहता हूँ एक ही डेटा दो "शाखाओं", अलग से संसाधित करने के लिए फिर "में शामिल हो गए" में विभाजित किया जा करने के लिए ...मैं "ब्रांच" कंडिट कैसे बना सकता हूं?

       +----------+ 
       +---------+ -->| doublber |--- +--------+ 
    +--------+ |   |-- +----------+ -->|  | +------+ 
    | source |-->| splitter|      | summer |-->| sink | 
    +--------+ |   |-- +----------+ -->|  | +------+ 
       +---------+ -->| delayer |--- +--------+ 
           +----------+ 

मैं यह कैसे करना चाहिए?

मेरे प्रयास:

import Data.Conduit 
import Control.Monad.IO.Class 
import qualified Data.Conduit.List as CL 
-- import Data.Conduit.Internal (zipSources) 
import Control.Arrow ((>>>)) 

source :: Source IO Int 
source = do 
    x <- liftIO $ getLine 
    yield (read x) 
    source 

splitter :: Conduit Int IO (Int, Int) 
splitter = CL.map $ \x -> (x,x) 

doubler = CL.map (* 2) 

delayer :: Conduit Int IO Int 
delayer = do 
    yield 0 
    CL.map id 

twoConduitBranches :: Monad m => Conduit a m b -> Conduit c m d -> Conduit (a,b) m (c,d) 
twoConduitBranches q w = awaitForever $ \(x, y) -> do 
    out1 <- undefined q x 
    out2 <- undefined w y 
    yield (out1, out2) 


summer :: Conduit (Int,Int) IO Int 
summer = CL.map $ \(x,y) -> x + y 

sink :: Sink Int IO() 
sink = CL.mapM_ (show >>> putStrLn) 

-- combosrc = zipSources (source $= delayer) (source $= doubler) 
main = source $= splitter $= twoConduitBranches doubler delayer $= summer $$ sink 

क्या मैं undefined रों के स्थान पर लिखना चाहिए?

उत्तर

3

आप ऐसा कर सकते हैं, लेकिन यह बदसूरत है, और उम्मीद है कि कार्यान्वयन यह स्पष्ट कारण है कि यह बदसूरत है कर देगा और नहीं एक अंतर्निहित नाली की सुविधा:

twoConduitBranches :: Monad m => Conduit a m c -> Conduit b m d -> Conduit (a,b) m (c,d) 
twoConduitBranches q w = getZipConduit 
     (ZipConduit (CL.map fst =$= q =$= CL.map Left) 
    <* ZipConduit (CL.map snd =$= w =$= CL.map Right)) =$= collapse 
    where 
    collapse = do 
     v1 <- await 
     case v1 of 
      Nothing -> return() 
      Just (Left _) -> error "out of sequence 1" 
      Just (Right d) -> do 
       v2 <- await 
       case v2 of 
        Nothing -> error "mismatched count" 
        Just (Right _) -> error "out of sequence 2" 
        Just (Left c) -> do 
         yield (c, d) 
         collapse 

(नोट: अपने प्रकार हस्ताक्षर एक मैं बदलाव बिट, मुझे लगता है इस प्रकार के हस्ताक्षर क्या तुम सच में चाहते थे है)

यहाँ दृष्टिकोण है:। एक Conduit कि आने वाली प्रत्येक टपल से पहले मान लेता में q बारी है, और फिर Left साथ इसके उत्पादन लपेट दें। इसी तरह, हम प्रत्येक आने वाले ट्यूपल से दूसरा मान लेते हैं और इसे w पर पास करते हैं, और फिर Right के साथ आउटपुट को लपेटें।

अब इन Conduit रों एक ही प्रकार (वे एक ही इनपुट tuples में लेते हैं, और एक ही या तो मूल्यों उत्पन्न), हम उन्हें, ZipConduit का उपयोग कर गठबंधन जो सभी घटकों के बीच इनपुट साझा करता है और एक भी धारा में उत्पादन coalesces है ।

यह स्ट्रीम Either c d की स्ट्रीम है, वांछित (c, d) नहीं। यह अंतिम रूपांतरण करने के लिए, हम collapse का उपयोग करते हैं। यह Right और Left मान को पॉप करता है, और उसके बाद उन्हें एक एकल ट्यूपल में डाल देता है जो इसे उत्पन्न करता है।

इस समारोह मानता है कि उत्पादन मूल्यों के अनुक्रम हमेशाw से एक मूल्य है, और फिर q से एक हो जाएगा। अगर कुछ और होता है, तो यह एक अपवाद फेंक देगा। समस्या यह है कि इस बात का अर्थ यह है कि वे वास्तव में उसी दर पर आउटपुट उत्पन्न करेंगे। वास्तव में, कंडिट विशेष रूप से पर से बचने के लिए डिज़ाइन किया गया है!

तो, यदि आप जानते हैं कि आपके दो घटक कंडिट हमेशा एक ही दर पर उत्पादन का उत्पादन करेंगे, तो यह कार्य काम करेगा। लेकिन आम तौर पर यह सच नहीं होगा।

संबंधित मुद्दे