2014-06-18 8 views
5

मैं अभी भी हास्केल के साथ संघर्ष कर रहा हूँ और अब मैं चारों ओर इनपुट/आउटपुट इकाई from this example मेरे मन लपेटकर के साथ एक समस्या का सामना करना पड़ा:समझना आई/ओ इकाई

main = do 
line <- getLine 
if null line 
    then return() 
    else do 
     putStrLn $ reverseWords line 
     main 

reverseWords :: String -> String 
reverseWords = unwords . map reverse . words 

मैं समझता हूँ कि हास्केल तरह कार्यात्मक भाषा पर आधार नहीं कर सकते क्योंकि कार्यों के साइड इफेक्ट्स, कुछ समाधान का आविष्कार किया जाना था। इस मामले में ऐसा लगता है कि सब कुछ do ब्लॉक में लपेटा जाना है। मुझे सरल उदाहरण मिलते हैं, लेकिन इस मामले में मुझे वास्तव में कुछ स्पष्टीकरण की आवश्यकता है।

आई/ओ कार्यों के लिए एक, एकल do ब्लॉक का उपयोग करने के लिए पर्याप्त क्यों नहीं है? यदि आपको/else मामले में पूरी तरह से नया क्यों खोलना है? साथ ही, मुझे नहीं पता कि इसे कैसे कॉल किया जाए, do मोनैड का 'दायरा' समाप्त होता है यानी आप मानक हास्केल नियम/फ़ंक्शंस का उपयोग कब कर सकते हैं?

+1

'do' केवल सिंटैक्टिक चीनी है जो '>> =' और '>>' के साथ अत्यधिक जटिल वक्तव्य लिखने से बचने के लिए है, यह सभी monads के साथ काम करता है, और आईओ के साथ कोई विशेष संबंध नहीं है। आपको उदाहरण कोड में दूसरे 'डू' का उपयोग करने की आवश्यकता नहीं है (आपको पहले 'do' की भी आवश्यकता नहीं है, लेकिन परिणामी कोड पढ़ने के लिए कठिन होगा), आप' else putStrLn (रिवर्सवर्ड लाइन) भी लिख सकते हैं >> मुख्य 'और इसका एक ही प्रभाव होगा। –

+0

मैंने यहां काफी हद तक समान प्रश्न का उत्तर दिया है: http://stackoverflow.com/questions/23049409/simple-haskell-code-cant-compile/23050814#23050814 क्या इससे मदद मिलती है? यह चाल मूल रूप से सभी कार्यों के रिटर्न प्रकारों को देखना है, और सब कुछ जगह में गिर जाएगा। – iamnat

+0

http://stackoverflow.com/questions/2488646/why-are-side-effects-modeled-as-monads-in-haskell?rq=1 में कुछ और स्पष्टीकरण हैं। – dfeuer

उत्तर

8

do ब्लॉक पहले संकेत के समान इंडेंटेशन स्तर पर से संबंधित कुछ भी चिंता करता है। तो अपने उदाहरण में यह वास्तव में सिर्फ दो चीजों को एक साथ लिंक कर रहा है:

line <- getLine 

और सभी बाकी है, जो होता है बल्कि बड़ा हो:

if null line 
    then return() 
    else do 
     putStrLn $ reverseWords line 
     main 

लेकिन कोई कितना जटिल, do वाक्य रचना नहीं है इन अभिव्यक्तियों को पर देखें। तो यह सब बिल्कुल के रूप में

main :: IO() 
main = do 
    line <- getLine 
    recurseMain line 
सहायक समारोह के साथ

ही है

recurseMain :: String -> IO() 
recurseMain line 
    | null line = return() 
    | otherwise = do 
      putStrLn $ reverseWords line 
      main 

अब, जाहिरrecurseMain में सामान नहीं जान सकता कि समारोह मुख्य रूप से एक do ब्लॉक के भीतर कहा जाता है , इसलिए आपको do का उपयोग करने की आवश्यकता है।

8

do वास्तव में कुछ भी नहीं करता है, यह आसानी से कथन संयोजन के लिए वाक्य रचनात्मक चीनी है।

आप एक से अधिक भाव है, तो आप उन्हें सूची में जोड़ सकते हैं : का उपयोग कर: एक संदिग्ध सादृश्य तुलना करने के लिए do[] है

(1 + 2) : (3 * 4) : (5 - 6) : ... 

बहरहाल, यह कष्टप्रद है, इसलिए हम बजाय [] अंकन, उपयोग कर सकते हैं जो

[1+2, 3*4, 5-6, ...] 

इसी प्रकार, यदि आप एक से अधिक आईओ statments है, तो आप can combine them using >> and >>=: एक ही बात करने के लिए संकलित

+०१२३५१६४१०६१
(putStrLn "What's your name?") >> getLine >>= (\name -> putStrLn $ "Hi " ++ name) 

बहरहाल, यह कष्टप्रद है, इसलिए हम बजाय do अंकन है, जो एक ही बात करने के लिए संकलित उपयोग कर सकते हैं:

do 
    putStrLn "What's your name?" 
    name <- getLine 
    putStrLn $ "Hi " ++ name 

अब क्यों आप एक से अधिक do ब्लॉक की जरूरत का जवाब सरल है:

यदि आपके पास मानों की एकाधिक सूचियां हैं, तो आपको एकाधिक [] s (भले ही वे नेस्टेड हैं) की आवश्यकता हो।

यदि आपके पास मोनैडिक स्टेटमेंट्स के एकाधिक अनुक्रम हैं, तो आपको एकाधिक do एस (भले ही वे घोंसला हो) की आवश्यकता हो।

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