2012-03-02 17 views
5

द्वारा फ़ाइल को एक फ़ाइल पढ़ें मैंने हाल ही में Waterloo CCC किया था और मुझे लगता है कि हास्केल इन प्रकार के सवालों के जवाब देने के लिए एकदम सही भाषा है। मैं अभी भी इसे सीख रहा हूँ। हालांकि, मैं इनपुट के साथ थोड़ा संघर्ष कर रहा हूं।हास्केल:

यहाँ मैं क्या उपयोग कर रहा हूँ है:

import IO 
import System.Environment 
import System.FilePath 

… 

main = do 
    name <- getProgName 
    args <- getArgs 
    input <- readFile $ 
     if not (null args) 
      then head args 
      else dropExtension name ++ ".in" 
    let (k:code:_) = lines input 
    putStrLn $ decode (read k) code 

आप देख सकते हैं, मैं, कमांड लाइन दी फ़ाइल पथ से या उदाहरण के लिए j1.in से पढ़ रहा हूँ अगर इस कार्यक्रम j1.hs कहा जाता है और करने के लिए संकलित किया गया है j1

मुझे केवल फाइल की पहली दो पंक्तियों में दिलचस्पी है, इसलिए मैंने उन पंक्तियों को प्राप्त करने के लिए पैटर्न मिलान का उपयोग किया है और उन्हें k और code पर इस उदाहरण में बांध दिया है। और फिर मैं एक पूर्णांक के रूप में k पढ़ता हूं और इसे decode फ़ंक्शन पर कोड स्ट्रिंग पास करता हूं, जिसे मैं आउटपुट करता हूं।

मुझे आश्चर्य है कि readFile पूरी फ़ाइल को स्मृति में लोड कर रहा है, जो खराब होगा। लेकिन फिर मैंने सोचना शुरू कर दिया, शायद हास्केल आलसी है, यह केवल पहले दो लाइनों को पढ़ता है क्योंकि बाद में यह सब पूछा जाता है। क्या मैं सही हू?

इसके अलावा, अगर उस कोड नमूने के साथ कुछ भी है जो बेहतर या अधिक मूर्खतापूर्ण हो सकता है, तो कृपया मुझे बताएं।

उत्तर

8

documentation for readFile का कहना है:

readFile समारोह एक फ़ाइल पढ़ता है और एक स्ट्रिंग के रूप फ़ाइल की सामग्री देता है। फ़ाइल को getContents के साथ मांग पर आलसी पढ़ा जाता है।

तो हाँ, यह केवल फ़ाइल की पहली दो पंक्तियों को पढ़ना होगा (बफरिंग का मतलब है कि यह शायद दृश्यों के पीछे और अधिक पढ़ेगा)। लेकिन यह readFile की विशेष रूप से संपत्ति है, सामान्य रूप से सभी हास्केल I/O कार्यों में से नहीं।

आलसी आई/ओ आई/ओ-भारी कार्यक्रमों (जैसे वेबसर्वर) के लिए एक बुरा विचार है, लेकिन यह सरल कार्यक्रमों के लिए अच्छी तरह से काम करता है जो अधिक I/O नहीं करते हैं।

+0

एक ट्यूटोरियल में 'hSetBuffering stdin LineBuffering' मैंने stdin के लिए उपयोग किया था क्योंकि इनपुट केवल एक ही समय में एक पंक्ति में प्रवेश किया जाएगा; फ़ाइल इनपुट के बराबर होगा? यदि इसका उपयोग करना समझ में आता है या इसे समयपूर्व अनुकूलन माना जाएगा? – mk12

+3

मैं आपके बिंदु से असहमत हूं कि अनिवार्य रूप से आलसी I/O केवल तभी उपयोगी होता है जब यह छोटा हो। आई/ओ-भारी सेटिंग्स में आलसी I/O की एक बहुत ही उपयोगी विशेषता का एक उदाहरण - यह है कि डिफ़ॉल्ट रूप से डेटा हैंडलिंग इनस्थल है, जिसका अर्थ डेटा की बड़ी मात्रा के लिए बहुत ही कुशल है। – amindfv

+0

@amindfv: वह यह नहीं कहता कि आलसी I/O बड़े कार्यक्रमों के लिए _useless_ है, वह कहता है कि यह _bad_ है। उसका मतलब यह है कि आलसी आईओ अक्सर संसाधन लीक की ओर जाता है (यहां फ़ाइल कभी भी बंद नहीं होती है क्योंकि यह इसके अंत तक नहीं पढ़ी जाती है) जो बड़े और जटिल कार्यक्रमों में सही करना मुश्किल है। स्ट्रीमिंग के लिए अधिक सिद्धांतबद्ध समाधानों को प्राथमिकता दी जानी चाहिए (जैसे Iteratee या अधिक हालिया कंडिट) क्योंकि वे आपको बेहतर नियंत्रण देते हैं। – Jedai

6

हां, readFile आलसी है। यदि आप इसके बारे में स्पष्ट होना चाहते हैं, तो आप इसका उपयोग कर सकते हैं:

import Control.Monad (replicateM) 
import System.IO 

readLines n f = withFile f ReadMode $ replicateM n . hGetLine 

-- in main 
    (k:code:_) <- readLines 2 filename 

यह सुनिश्चित करेगा कि फ़ाइल जितनी जल्दी हो सके बंद हो।

लेकिन जिस तरह से आपने इसे किया है वह ठीक है।

3

readFile फ़ाइल को आलसी पढ़ता है, इसलिए जब तक आप पूरी फ़ाइल का उपयोग नहीं करते हैं, तब तक यह पूरी फ़ाइल को स्मृति में नहीं पढ़ेगी। यह आम तौर पर पहली दो पंक्तियों को नहीं पढ़ेगा, क्योंकि यह ब्लॉक में पढ़ता है, लेकिन यह दूसरी नई लाइन को खोजने के लिए आवश्यकतानुसार कई ब्लॉक पढ़ेगा।

2

हास्केल में I/O आमतौर पर आलसी नहीं होता है। हालांकि, readFile फ़ंक्शन विशेष रूप से आलसी है।

अन्य ने भी यही कहा है। मैंने जो कुछ भी नहीं देखा है, वह अभी तक यह है कि आपके द्वारा खोला गया फ़ाइल तब तक बंद नहीं होगा जब तक प्रोग्राम समाप्त नहीं होता है या कचरा कलेक्टर चलता है। इसका मतलब यह है कि ओएस फ़ाइल हैंडल को आवश्यक से अधिक समय तक खुला रखा जा सकता है। आपके कार्यक्रम में शायद कोई बड़ा सौदा नहीं है। लेकिन एक और जटिल परियोजना में, यह हो सकता है।