2014-12-29 8 views
5

मैं एक पाइप से 50 आइटम तक के समूह को पढ़ने की कोशिश कर रहा हूं और उन्हें एक बार में एक आईओ क्रिया में संसाधित कर रहा हूं। (इसके लिए उपयोग का मामला है कि मैं डेटाबेस में डेटा डालने की कोशिश कर रहा हूं और मैं एक लेनदेन के अंदर एक संपूर्ण बैच करना चाहता हूं क्योंकि यह काफी अधिक कुशल है)। यहाँ मैं अब तक क्या मिल गया है की एक सरलीकृत संस्करण है:पाइप के साथ इनपुट के अंत का पता लगाने के लिए

type ExampleType = Int 

doSomething :: [ExampleType] -> IO() 
doSomething = undefined 

inGroupsOf50 :: Monad m => Producer ExampleType m() -> m() 
inGroupsOf50 input = 
    runEffect $ input >-> loop 
     where loop = do entries <- replicateM 50 await 
        lift $ doSomething entries --Insert a bunch all in one transaction 
        loop 

समस्या जहाँ तक मैं बता सकता है, जब तक सम्मिलित करने के लिए आइटम्स की संख्या 50 से विभाजित करने के लिए होता है, मैं याद करने जा रहा हूँ कुछ। replicateM 50 await की बजाय मैं वास्तव में क्या चाहता हूं वह कुछ ऐसा है जो इनपुट समाप्त होने पर मुझे 50 आइटम या उससे कम तक देता है लेकिन मैं इसे लिखने के बारे में बिल्कुल नहीं समझ सकता।

मुझे लगता है कि pipes-parse देखने के लिए सही लाइब्रेरी हो सकती है। draw में एक आशाजनक हस्ताक्षर दिखता है ... लेकिन अभी तक सभी बिट्स मेरे सिर में एक साथ फिट नहीं हैं। मेरे पास producer है, मैं consumer लिख रहा हूं और मुझे वास्तव में यह नहीं मिलता है कि यह parser की अवधारणा से कैसे संबंधित है।

उत्तर

11

pipes-parse से भी अधिक आप शायद pipes-group पर एक नज़र डालना चाहते हैं। विशेष रूप से, के समारोह की जांच करते हैं

-- this type is slightly specialized 
chunksOf 
    :: Monad m => 
    Int -> 
    Lens' (Producer a m x) (FreeT (Producer a m) m x) 

Lens' बिट शायद डरावना है, लेकिन जल्दी से समाप्त किया जा सकता: यह कहा गया है कि हम में बदल सकते हैं Producer a m xFreeT (Producer a m) m x को [0]

import Control.Lens (view) 

chunkIt :: Monad m => Int -> Producer a m x -> FreeT (Producer a m) m x 
chunkIt n = view (chunksOf n) 

तो अब हम करने के लिए है पता लगाएं कि FreeT बिट के साथ क्या करना है। विशेष रूप से, हम free पैकेज में खुदाई और समारोह iterT

iterT 
    :: (Functor f, Monad m) => 
    (f (m a) -> m a) -> 
    (FreeT f m a -> m a) 

इस समारोह, iterT बाहर खींच, चलो हमें "उपभोग" एक FreeT एक समय में एक "कदम" बताना चाहते हैं जा रहे हैं। यह समझने के लिए, हम पहले iterT के प्रकार के विशेषज्ञ Producer a m

runChunk :: Monad m => 
      (Producer a m (m x)  -> m x) -> 
      (FreeT (Producer a m) m x -> m x) 
runChunk = iterT 

विशेष रूप से साथ f को बदलने के लिए होगा, runChunk कर सकते हैं "रन" एक FreeTProducer से भरा इतने लंबे समय हम यह बताने के लिए एक Producer a m (m x) कन्वर्ट करने के लिए के रूप में है m -action में। यह अधिक परिचित दिखने लग सकता है। जब हम runChunk के पहले तर्क को परिभाषित करते हैं तो हमें बस Producer निष्पादित करना होगा, इस मामले में, चयनित तत्वों की संख्या से अधिक नहीं होगा।

लेकिन प्रभावी वापसी मूल्य m x के साथ क्या हो रहा है? यह "निरंतरता" है, उदा। के बाद आने वाले सभी भाग जो आप लिख रहे हैं। तो, उदाहरण के लिए, मान लेते हैं कि हम एक Char की Producer रों मिल गया है चलो और हम 3 अक्षरों

के बाद प्रिंट और LINEBREAK करना चाहते हैं
main :: IO() 
main = flip runChunk (chunkIt 3 input) $ \p -> _ 

इस बिंदु पर _ छेद पर संदर्भ में p साथ IO() टाइप है p :: Producer Char IO (IO()) टाइप करें। हम for के साथ इस पाइप का उपभोग कर सकते हैं, इसके रिटर्न प्रकार (जो निरंतरता है, फिर से) इकट्ठा कर सकते हैं, एक नई लाइन को उत्सर्जित कर सकते हैं, और फिर निरंतरता को चला सकते हैं।

input :: Monad m => Producer Char m() 
input = each "abcdefghijklmnopqrstuvwxyz" 

main :: IO() 
main = flip runChunk (chunkIt 3 input) $ \p -> do 
    cont <- runEffect $ for p (lift . putChar) 
    putChar '\n' 
    cont 

और यह बिल्कुल के रूप में वांछित

λ> main 
abc 
def 
ghi 
jkl 
mno 
pqr 
stu 
vwx 
yz 

स्पष्ट है कि, जब मैं प्रदर्शनी का एक सा किया था व्यवहार करती है, यह काफी सरल कोड एक बार आप देखते हैं कि कैसे सभी टुकड़ों को एक साथ फिट है। यहां पूरी सूची दी गई है:

input :: Monad m => Producer Char m() 
input = each "abcdefghijklmnopqrstuvwxyz" 

main :: IO() 
main = flip iterT (input ^. chunksOf 3) $ \p -> do 
    cont <- runEffect $ for p $ \c -> do 
    lift (putChar c) 
    putChar '\n' 
    cont 

[0] इसके अलावा थोड़ा सा, लेकिन यह अभी के लिए पर्याप्त है।

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