2017-05-15 4 views
6

मैं ListT के विषय में pipes tutorial में प्रस्तुत उदाहरणों में से एक की समझ बनाने के लिए कोशिश कर रहा हूँ: उदाहरण के ऊपर से चलाया जाता हैपाइप्स ट्यूटोरियल: ListT उदाहरण

import Pipes 
import qualified Pipes.Prelude as P 

input :: Producer String IO() 
input = P.stdinLn >-> P.takeWhile (/= "quit") 

name :: ListT IO String 
name = do 
    firstName <- Select input 
    lastName <- Select input 
    return (firstName ++ " " ++ lastName) 

, तो हम निम्नलिखित की तरह उत्पादन मिलता है:

>>> runEffect $ every name >-> P.stdoutLn 
Daniel<Enter> 
Fischer<Enter> 
Daniel Fischer 
Wagner<Enter> 
Daniel Wagner 
quit<Enter> 
Donald<Enter> 
Stewart<Enter> 
Donald Stewart 
Duck<Enter> 
Donald Duck 
quit<Enter> 
quit<Enter> 
>>> 

ऐसा लगता है कि:

  1. आप इस (GHCi पर), पहला नाम आप इनपुट Wil चलाते हैं मैं बाध्य हो जाता हूं और केवल दूसरा बदल जाएगा। मैं उम्मीद करता हूं कि दोनों उत्पादक (Select input द्वारा परिभाषित) इनपुट पढ़ने पर मोड़ ले सकते हैं (शायद गैर-निर्धारक रूप से)।
  2. quit दर्ज करना एक बार पहले नाम को फिर से बांधने की अनुमति देगा। दोबारा, मैं यह देखने में असफल रहा कि क्यों firstName उपयोगकर्ता द्वारा दर्ज किए गए पहले मान से जुड़ा होगा।
  3. पंक्ति में दो बार quit दर्ज करना प्रोग्राम को समाप्त कर देगा। हालांकि, मैं उम्मीद करता हूं कि quit को प्रोग्राम छोड़ने के लिए केवल दो बार प्रवेश करना होगा (संभवतः अन्य इनपुट के साथ वैकल्पिक)।

मुझे ऊपर दिए गए उदाहरण के तरीके के बारे में कुछ मौलिक याद आ रही है, लेकिन मैं नहीं देख सकता।

उत्तर

9

जब आप इसे (जीएचसीआई पर) चलाते हैं, तो आपके द्वारा इनपुट किया जाने वाला पहला नाम बाध्य होगा और केवल दूसरा बदल जाएगा। मैं उम्मीद करता हूं कि दोनों उत्पादक (Select input द्वारा परिभाषित) इनपुट पढ़ने पर मोड़ लेते हैं (शायद गैर-निर्धारक रूप से)।

ListT इस तरह से काम नहीं करता है। इसके बजाय, यह "गहराई-पहले" है। हर बार जब यह पहला नाम मिलता है, तो यह अंतिम नामों की पूरी सूची को फिर से शुरू करना शुरू कर देता है।

उदाहरण ऐसा नहीं करता है, लेकिन अंतिम नामों की प्रत्येक सूची पहले नाम पर पहले नाम पर निर्भर हो सकती है। इस तरह:

input' :: String -> Producer String IO() 
input' msg = 
    (forever $ do 
     liftIO $ putStr msg 
     r <- liftIO $ getLine 
     yield r 
    ) >-> P.takeWhile (/= "quit") 

name' :: ListT IO String 
name' = do 
    firstName <- Select input 
    lastName <- Select $ input' $ "Enter a last name for " ++ firstName ++ ": " 
    return (firstName ++ " " ++ lastName) 

छोड़ने में प्रवेश एक बार पहला नाम फिर से बाध्य करने के लिए अनुमति देगा। दोबारा, मैं यह देखने में असफल रहा कि क्यों पहले नाम उपयोगकर्ता द्वारा दर्ज किए गए पहले मान से बंधेगा।

यदि हम अंतिम नाम पढ़ रहे हैं और एक छोड़ने की आज्ञा का सामना कर रहे हैं, तो "शाखा" समाप्त हो जाती है और हम सूची से दूसरे नाम को पढ़ने के लिए ऊपर के स्तर पर वापस जाते हैं। आखिरी नामों को पढ़ने वाली "प्रभावशाली सूची" केवल हमारे द्वारा काम करने के लिए पहला नाम होने के बाद ही बनाई जाती है।

पंक्ति में दो बार quit दर्ज करना प्रोग्राम को समाप्त कर देगा। हालांकि, मैं उम्मीद करता हूं कि quit को केवल प्रोग्राम (संभवतः अन्य इनपुट के साथ वैकल्पिक) छोड़ने के लिए दो बार प्रवेश करना होगा।

ध्यान दें कि शुरुआत में एक ही छोड़ने में प्रवेश करने से कार्यक्रम समाप्त हो जाएगा, क्योंकि हम पहले नामों की शीर्ष-स्तर सूची को "बंद" कर रहे हैं।

असल में, हर बार जब आप quit दर्ज करते हैं तो आप वर्तमान शाखा को बंद करते हैं और "खोज पेड़" में एक स्तर पर जाते हैं। प्रत्येक बार जब आप पहला नाम दर्ज करते हैं तो आप एक स्तर पर जाते हैं।

+2

ए साइड नोट बन: 'ListT'," पुनरावृत्ति इकाई ट्रांसफार्मर "मॉड्यूल में' 'free' पैकेज के Control.Monad.Trans.Iter' के विपरीत जाने करता है 'MonadPlus' उदाहरण का उपयोग करके" पैरालेल में "कार्रवाइयों की प्रभावशाली सूचियां लिखें। http://hackage.haskell.org/package/free-4.12.4/docs/Control-Monad-trans-Iter.html https://gist.github.com/danidiaz/e9382127d1c4025b9845 – danidiaz

0

@ danidiaz के महान जवाब देने के लिए जोड़ने के लिए, आप कर सकते हैं एक firstName फिर उत्साह name के व्यवहार मिलता है, बजाय सिर्फ lastName रों के लिए पूछ रहा रखने के लिए।

आप क्या कर सकते Monad m => ListT m की MonadZip उदाहरण का इस्तेमाल करते हैं, विशेष रूप से

mzip :: Monad m => ListT m a -> ListT m b -> ListT m (a, b). 

इस प्रकार है, तो आप name रूप

name :: ListT IO String 
name = do 
    (firstName, lastName) <- mzip (Select input) (Select input) 
    return (firstName ++ " " ++ lastName) 

निर्धारित कर सकते हैं और आप अपने बारी व्यवहार मिलता है।

एक अच्छा तरफ के रूप में, आप MonadComprehensions और ParallelListComp एक्सटेंशन का भी उपयोग कर सकते हैं। इन का उपयोग करना, name के दो संस्करणों

name :: ListT IO String 
name = [ firstName ++ " " ++ lastName | firstName <- Select input 
             , lastName <- Select input ] 

name' :: ListT IO String 
name' = [ firstName ++ " " ++ lastName | firstName <- Select input 
             | lastName <- Select input ] 
संबंधित मुद्दे