2013-09-02 5 views
10

मेरे पास हैकेल में एक प्रोग्राम है जिसे उपयोगकर्ता से इनपुट की मनमानी रेखाएं पढ़नी पड़ती हैं और जब उपयोगकर्ता समाप्त हो जाता है तो संचित इनपुट को किसी फ़ंक्शन पर भेजा जाना होता है।हास्केल - उपयोगकर्ता इनपुट पर लूप

एक जरूरी प्रोग्रामिंग भाषा इस इस प्रकार दिखाई देगा में:

content = '' 
while True: 
    line = readLine() 
    if line == 'q': 
     break 
    content += line 
func(content) 

मैं इस अविश्वसनीय रूप से मुश्किल Haskell में करने के लिए तो मैं वहाँ अगर एक haskell बराबर जानना चाहते हैं पाते हैं।

उत्तर

7

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

getUserLines :: IO String      -- optional type signature 
getUserLines = go "" 
    where go contents = do 
    line <- getLine 
    if line == "q" 
     then return contents 
     else go (contents ++ line ++ "\n")  -- add a newline 

यह वास्तव में एक आईओ कार्रवाई जो एक String रिटर्न की एक परिभाषा है। चूंकि यह एक आईओ क्रिया है, इसलिए आप = असाइनमेंट सिंटैक्स की बजाय <- वाक्यविन्यास का उपयोग करके लौटाई गई स्ट्रिंग तक पहुंच सकते हैं। यदि आप एक त्वरित अवलोकन चाहते हैं, तो मैं The IO Monad For People Who Simply Don't Care पढ़ने की अनुशंसा करता हूं।

आप की तरह GHCi प्रॉम्प्ट पर इस सुविधा का उपयोग कर सकते हैं इस

>>> str <- getUserLines 
Hello<Enter>  -- user input 
World<Enter>  -- user input 
q<Enter>   -- user input 
>>> putStrLn str 
Hello   -- program output 
World   -- program output 
+1

अब, क्या आप वास्तव में हास्केल में इसे लिखेंगे? 'Line' में 'सामग्री' को हर बार जोड़ना आपको खराब प्रदर्शन देता है। 'सामग्री' जो आप अंत में चाहते हैं वह एक उपसर्ग है कि 'getContents' के लिए एक कॉल आपको क्या देगी। – nickie

+1

यह एक उचित बिंदु है - लेकिन मैंने सोचा कि यह आईओ मोनैड में काम करने के लिए एक महसूस करने के लिए "ग्राउंड अप से" कैसे करना है, यह समझाने लायक था (जो शायद नए लोगों के लिए हास्केल का सबसे भ्रमित हिस्सा है)। इनपुट में किए जाने वाले प्रसंस्करण से उपयोगकर्ता इनपुट को अलग करने का भी लाभ होता है, जिसका आपका उत्तर नहीं है। मैं 'getContents.' –

+0

के बारे में एक परिशिष्ट जोड़ूंगा, ठीक है, मैं अपना प्रारंभिक -1 वापस ले रहा हूं। लेकिन, शैक्षणिक उद्देश्यों को छोड़ दिया गया, मैं इस बुरे हास्केल जैसे कोड पर विचार करूंगा। जो लोग देखभाल करते हैं, कम से कम ... :-) – nickie

16

पुनरावृत्ति के बराबर हास्केल रिकर्सन है। यदि आपको इनपुट की रेखाएं पढ़नी होंगी तो आपको IO मोनैड में भी काम करने की आवश्यकता होगी। सामान्य तस्वीर है:

import Control.Monad 

main = do 
    line <- getLine 
    unless (line == "q") $ do 
    -- process line 
    main 

तुम सिर्फ content में सभी पढ़ने लाइनों जमा करने के लिए चाहते हैं, आप ऐसा करने की जरूरत नहीं है। बस getContents का उपयोग करें जो सभी उपयोगकर्ता इनपुट को पुनर्प्राप्त (आलसी) करेगा। जब आप 'q' देखते हैं तो बस रुकें। काफी मुहावरेदार हास्केल में, पढ़ने कोड की एक पंक्ति में किया जा सकता है:

main = mapM_ process . takeWhile (/= "q") . lines =<< getContents 
    where process line = do -- whatever you like, e.g. 
          putStrLn line 

आप दाएं से बाएं कोड की पहली पंक्ति पढ़ते हैं, यह कहते हैं:

  1. प्राप्त सबकुछ जो उपयोगकर्ता इनपुट के रूप में प्रदान करेगा (कभी डर नहीं, यह आलसी है);

  2. इसे लाइनों में विभाजित करता है जैसा कि यह आता है;

  3. केवल तब तक लाइनें लें जब तक वे "क्यू" के बराबर न हों, जब आप ऐसी रेखा देखते हैं तो रोकें;

  4. और प्रत्येक पंक्ति के लिए process पर कॉल करें।

यदि आप इसे पहले से नहीं समझ पाए हैं, तो आपको ध्यान से एक हास्केल ट्यूटोरियल पढ़ने की आवश्यकता है!

+0

मैं readLn के बजाय getLine प्रयोग करेंगे निष्पादन योग्य संस्करण प्राप्त करने के लिए, और भी जोड़ने 'आयात – jev

+0

@jev Control.Monad', पर सहमत हुए। मैंने इसे अधिक सामान्य बनाने के लिए 'readLn' का उपयोग किया, लेकिन यह किसी ऐसे व्यक्ति के लिए भ्रमित हो सकता है जो सिर्फ लाइनों को पढ़ना चाहता है। – nickie

1
कुछ

आप कर सकता है

import Control.Applicative ((<$>)) 

input <- unlines . takeWhile (/= "q") . lines <$> getContents 

इनपुट होगा क्या उपयोगकर्ता तक लिखा था (लेकिन सहित नहीं) की तरह क्यू।

2

का उपयोग pipes-4.0 है, जो इस सप्ताह के अंत बाहर आ रहा है:

import Pipes 
import qualified Pipes.Prelude as P 

f :: [String] -> IO() 
f = ?? 

main = do 
    contents <- P.toListM (P.stdinLn >-> P.takeWhile (/= "q")) 
    f contents 

स्मृति में सभी लाइनों को लोड करता है। हालांकि, अगर आप भी प्रत्येक पंक्ति के रूप में यह उत्पन्न किया जा रहा है, भी संसाधित कर सकते हैं:

f :: String -> IO() 

main = runEffect $ 
    for (P.stdinLn >-> P.takeWhile (/= "q")) $ \str -> do 
     lift (f str) 

कि इनपुट स्ट्रीम जाएगा और स्मृति में एक से अधिक पंक्ति लोड कभी नहीं।

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