2016-02-01 21 views
8

मैं अपना खुद का sum फ़ंक्शन लिखकर pipes पैकेज सीखने की कोशिश कर रहा हूं और मैं स्टंप हो रहा हूं। मैं Pipes.Prelude से उपयोगिता कार्यों का उपयोग नहीं करना चाहता (क्योंकि इसमें sum और fold और अन्य फ़ंक्शन जो इसे छोटा बनाते हैं) और केवल Pipes.Tutorial में वर्णित जानकारी का उपयोग करें। ट्यूटोरियल Proxy के रचनाकारों के बारे में बात नहीं करता है, लेकिन अगर मैं sum और fold के स्रोत में देखता हूं तो यह उन रचनाकारों का उपयोग करता है और मुझे आश्चर्य है कि इन निम्न स्तर के विवरणों के बिना मेरे sum फ़ंक्शन को लिखना संभव है या नहीं।हास्केल पाइप्स "योग" फ़ंक्शन कैसे लिखें?

मुझे इस बात के साथ आने में परेशानी हो रही है कि यह फ़ंक्शन मूल्यों को तब तक जारी रखने में सक्षम होगा जब तक कि मूल्य उपलब्ध हों, और फिर किसी भी तरह उपयोगकर्ता को उस राशि को वापस कर दें। मुझे लगता है कि प्रकार होगा:

sum' :: Monad m => Consumer Int m Int 

यह मेरे लिए प्रकट होता है यह इस समारोह मूल्यों का उपभोग कर सकता है जब तक वहाँ कोई और अधिक कर रहे हैं, तब अंतिम राशि लौटने क्योंकि काम कर सकता था। मैं इसे इस तरह का प्रयोग करेंगे:

mysum <- runEffect $ inputs >-> sum' 

हालांकि, Pipes.Prelude में समारोह के बजाय निम्नलिखित हस्ताक्षर हैं:

sum :: (Monad m, Num a) => Producer a m() -> m a 

तो मुझे लगता है कि यह मेरी पहली बाधा है। sum फ़ंक्शन Producer को >-> का उपयोग करने के विरोध के रूप में एक तर्क के रूप में क्यों लेता है?


FYI करें मैं danidiaz से जवाब के बाद निम्नलिखित के साथ समाप्त हो गया:

sum' = go 0 
    where 
    go n p = next p >>= \x -> case x of 
     Left _  -> return n 
     Right (_, p') -> go (n + 1) p' 
+0

अच्छी तरह से 'पाइप में sum' कुछ है कि * * संख्या पैदा करता है और एक monadic कार्रवाई में उन्हें का सार लेता है ... विचार काफी समान है यदि आप इसके बारे में सोचते हैं तो आपके लिए भी - पैकेज भी डिज़ाइन किया गया है ताकि आपको विवरणों की परवाह नहीं करनी चाहिए, लेकिन 'फ़ोल्ड' और शेष प्रदान किए गए प्राइमेटिव्स का उपयोग करें;) – Carsten

उत्तर

5

Consumers वास्तव में काफी वे क्या कर सकते में सीमित हैं। वे अंत-इनपुट का पता नहीं लगा सकते हैं (pipes-parse उस के लिए एक अलग तकनीक का उपयोग करता है) और जब पाइपलाइन का कुछ अन्य भाग बंद हो जाता है (उदाहरण के लिए Producer अपस्ट्रीम) कि भाग वह है जो परिणाम के लिए परिणाम मूल्य प्रदान करना होगा पाइप लाइन। इसलिए Consumer के वापसी मूल्य में योग को सामान्य रूप से काम नहीं करेगा।

कुछ विकल्प हैं:

  • एक समारोह है कि Producer internals के साथ सीधे संबंधित है, या शायद next की तरह एक सहायक समारोह का उपयोग करता है को लागू करें। foldl पैकेज से Fold एस जैसे "स्मार्ट" उपभोक्ताओं को Producer डेटा खिला सकते हैं, इस प्रकार के एडेप्टर हैं।

  • एक Consumer, लेकिन इसके बजाय Consumer की वापसी मूल्य में राशि डालने की का उपयोग कर रखें, संचायक के रूप में एक Sum Int monoid के साथ आधार इकाई के रूप में एक WriterT का उपयोग करें। इस तरह, भले ही Producer पहले रुक जाए, फिर भी आप लेखक को संचयक प्राप्त करने के लिए चला सकते हैं, हालांकि यह समाधान कम कुशल होने की संभावना है।WriterT दृष्टिकोण के लिए

उदाहरण कोड:

import Data.Monoid 
import Control.Monad 
import Control.Monad.Trans.Writer 
import Pipes 

producer :: Monad m => Producer Int m() 
producer = mapM_ yield [1..10] 

summator :: Monad n => Consumer Int (WriterT (Sum Int) n)() 
summator = forever $ await >>= lift . tell . Sum 

main :: IO() 
main = do 
    Sum r <- execWriterT . runEffect $ producer >-> summator 
    print r 
+0

"एंड-ऑफ-इनपुट का पता नहीं लगा सकता" में गुम हो गया था। बहुत बहुत धन्यवाद। – Ana

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