Haskell Language
आईओ
खोज…
एक स्ट्रिंग में मानक इनपुट की सभी सामग्री को पढ़ना
main = do
input <- getContents
putStr input
इनपुट:
This is an example sentence.
And this one is, too!
आउटपुट:
This is an example sentence.
And this one is, too!
नोट: यह कार्यक्रम वास्तव में इनपुट के सभी से पहले उत्पादन के कुछ हिस्सों प्रिंट होगा पूरी तरह से पढ़ा जा चुका है इसका मतलब है कि, अगर, उदाहरण के लिए, आप का उपयोग करें। getContents
एक 50MiB फ़ाइल पर, हास्केल के आलसी मूल्यांकन और कचरा कलेक्टर है कि केवल यह सुनिश्चित करना होगा वर्तमान में आवश्यक फ़ाइल के कुछ हिस्सों (पढ़ें: आगे के निष्पादन के लिए अपरिहार्य) को मेमोरी में लोड किया जाएगा। इस प्रकार, 50MiB फ़ाइल को एक बार में मेमोरी में लोड नहीं किया जाएगा।
मानक इनपुट से एक पंक्ति पढ़ना
main = do
line <- getLine
putStrLn line
इनपुट:
This is an example.
आउटपुट:
This is an example.
मानक इनपुट से ऑब्जेक्ट को पार्स करना और बनाना
readFloat :: IO Float
readFloat =
fmap read getLine
main :: IO ()
main = do
putStr "Type the first number: "
first <- readFloat
putStr "Type the second number: "
second <- readFloat
putStrLn $ show first ++ " + " ++ show second ++ " = " ++ show ( first + second )
इनपुट:
Type the first number: 9.5
Type the second number: -2.02
आउटपुट:
9.5 + -2.02 = 7.48
फ़ाइल हैंडल से पढ़ना
आई / ओ लाइब्रेरी के कई अन्य हिस्सों की तरह, एक मानक स्ट्रीम का उपयोग करने वाले कार्यों में System.IO
में एक समकक्ष होता है जो समान कार्य करता है, लेकिन बाईं ओर एक अतिरिक्त पैरामीटर के साथ, Handle
का प्रकार, जो स्ट्रीम का प्रतिनिधित्व करता है संभाला। उदाहरण के लिए, getLine :: IO String
में एक प्रतिपक्ष hGetLine :: Handle -> IO String
।
import System.IO( Handle, FilePath, IOMode( ReadMode ),
openFile, hGetLine, hPutStr, hClose, hIsEOF, stderr )
import Control.Monad( when )
dumpFile :: Handle -> FilePath -> Integer -> IO ()
dumpFile handle filename lineNumber = do -- show file contents line by line
end <- hIsEOF handle
when ( not end ) $ do
line <- hGetLine handle
putStrLn $ filename ++ ":" ++ show lineNumber ++ ": " ++ line
dumpFile handle filename $ lineNumber + 1
main :: IO ()
main = do
hPutStr stderr "Type a filename: "
filename <- getLine
handle <- openFile filename ReadMode
dumpFile handle filename 1
hClose handle
फ़ाइल के example.txt
:
This is an example.
Hello, world!
This is another example.
इनपुट:
Type a filename: example.txt
आउटपुट:
example.txt:1: This is an example.
example.txt:2: Hello, world!
example.txt:3: This is another example
फ़ाइल की स्थिति के लिए जाँच करना
जिस तरह से अधिकांश अन्य भाषाओं के मानक I / O पुस्तकालय इसे करते हैं, isEOF
थोड़ा सा सहज, Haskell के isEOF
को EOF स्थिति की जांच करने से पहले आपको रीड ऑपरेशन करने की आवश्यकता नहीं होती है; रनटाइम यह आपके लिए करेगा।
import System.IO( isEOF )
eofTest :: Int -> IO ()
eofTest line = do
end <- isEOF
if end then
putStrLn $ "End-of-file reached at line " ++ show line ++ "."
else do
getLine
eofTest $ line + 1
main :: IO ()
main =
eofTest 1
इनपुट:
Line #1.
Line #2.
Line #3.
आउटपुट:
End-of-file reached at line 4.
एक पूरी फाइल से शब्द पढ़ना
हास्केल में, यह अक्सर भावना सब पर फ़ाइल हैंडल के साथ परेशान करने के लिए नहीं, बल्कि केवल पढ़ने के लिए या सीधे डिस्क से स्मृति को † एक पूरी फ़ाइल लिखते हैं, और सभी विभाजन / शुद्ध स्ट्रिंग डेटा संरचना के साथ पाठ का प्रसंस्करण कर बनाता है। यह IO और प्रोग्राम लॉजिक को मिलाने से बचता है, जो बग से बचने में बहुत मदद करता है।
-- | The interesting part of the program, which actually processes data
-- but doesn't do any IO!
reverseWords :: String -> [String]
reverseWords = reverse . words
-- | A simple wrapper that only fetches the data from disk, lets
-- 'reverseWords' do its job, and puts the result to stdout.
main :: IO ()
main = do
content <- readFile "loremipsum.txt"
mapM_ putStrLn $ reverseWords content
यदि loremipsum.txt
है
Lorem ipsum dolor sit amet,
consectetur adipiscing elit
तब प्रोग्राम आउटपुट होगा
elit
adipiscing
consectetur
amet,
sit
dolor
ipsum
Lorem
यहाँ, mapM_
फ़ाइल में सभी शब्दों की सूची से putStrLn
, और उनमें से प्रत्येक को putStrLn
साथ एक अलग पंक्ति में putStrLn
।
This यदि आपको लगता है कि यह स्मृति पर बेकार है, तो आपके पास एक बिंदु है। दरअसल, हास्केल का आलस्य अक्सर इस बात से बच सकता है कि पूरी फ़ाइल को एक साथ मेमोरी में रहने की जरूरत है ... लेकिन सावधान, इस तरह के आलसी आईओ के कारण समस्याओं का अपना सेट होता है। प्रदर्शन-महत्वपूर्ण अनुप्रयोगों के लिए, यह अक्सर पूरी फ़ाइल को एक बार में, सख्ती से पढ़ने के लिए लागू करने के लिए समझ में आता है; आप के साथ ऐसा कर सकते हैं Data.Text
के संस्करण Data.Text
readfile
। readFile
IO आपके प्रोग्राम की `मुख्य` क्रिया को परिभाषित करता है
हास्केल प्रोग्राम को निष्पादन योग्य बनाने के लिए आपको एक फाइल प्रदान करनी चाहिए जिसमें IO ()
का main
कार्य है IO ()
main :: IO ()
main = putStrLn "Hello world!"
जब हास्केल संकलित किया जाता है तो यह IO
डेटा की जांच करता है और इसे एक निष्पादन योग्य में बदल देता है। जब हम इस कार्यक्रम को चलाते हैं तो यह Hello world!
को प्रिंट करेगा Hello world!
।
यदि आपके पास टाइप IO a
मान हैं तो main
वे कुछ भी नहीं करेंगे।
other :: IO ()
other = putStrLn "I won't get printed"
main :: IO ()
main = putStrLn "Hello world!"
इस कार्यक्रम को संकलित करना और इसे चलाने का अंतिम उदाहरण के समान प्रभाव होगा। other
में कोड को अनदेखा किया गया है।
कोड को other
में बनाने के लिए रनटाइम प्रभाव पड़ता है जिसे आपको इसे main
से लिखना होता है। कोई IO
मान जो main
रूप से main
से रचित नहीं है, कोई रनटाइम प्रभाव होगा। दो की रचना करने के IO
मूल्यों क्रमिक रूप से आप उपयोग कर सकते हैं do
-notation:
other :: IO ()
other = putStrLn "I will get printed... but only at the point where I'm composed into main"
main :: IO ()
main = do
putStrLn "Hello world!"
other
जब आप इस प्रोग्राम को संकलित करते हैं और इसे चलाते हैं
Hello world!
I will get printed... but only at the point where I'm composed into main
ध्यान दें कि संचालन के क्रम का वर्णन इस बात से किया जाता है कि other
की रचना main
रूप से की गई थी और परिभाषा क्रम नहीं।
आइओ की भूमिका और उद्देश्य
हास्केल एक शुद्ध भाषा है, जिसका अर्थ है कि अभिव्यक्ति के दुष्प्रभाव नहीं हो सकते। एक साइड इफेक्ट कुछ भी है जो अभिव्यक्ति या फ़ंक्शन एक मूल्य का उत्पादन करने के अलावा करता है, उदाहरण के लिए, एक वैश्विक काउंटर को संशोधित करें या मानक आउटपुट पर प्रिंट करें।
हास्केल में, पक्ष-प्रभावकारी संगणना (विशेष रूप से, जिनका वास्तविक दुनिया पर प्रभाव हो सकता है) को IO
का उपयोग करके मॉडलिंग की जाती है। कड़ाई से बोलते हुए, IO
एक प्रकार का निर्माता है, एक प्रकार लेता है और एक प्रकार का उत्पादन करता है। उदाहरण के लिए, IO Int
एक आई / ओ गणना एक उत्पादन का प्रकार है Int
मूल्य। IO
प्रकार सार है, और के लिए प्रदान किए गए इंटरफ़ेस IO
सुनिश्चित करता है कि कुछ अवैध मूल्यों (है कि, गैर sensical प्रकार के साथ काम करता है) मौजूद नहीं कर सकते, यह सुनिश्चित करना कि सभी में निर्मित कार्य करता है जो आईओ प्रदर्शन में संलग्न एक वापसी प्रकार है द्वारा IO
।
जब एक हास्केल कार्यक्रम चलाया जाता है, गणना नामित हास्केल मान से दर्शाया main
, जिसका प्रकार किया जा सकता है IO x
के लिए किसी भी प्रकार के x
, मार डाला जाता है।
IO मूल्यों में हेरफेर
मानक पुस्तकालय में कई कार्य होते हैं जो विशिष्ट IO
क्रियाएं प्रदान करते हैं जिन्हें एक सामान्य प्रयोजन प्रोग्रामिंग भाषा को निष्पादित करना चाहिए, जैसे फ़ाइल हैंडल को पढ़ना और लिखना। सामान्य IO
कार्रवाइयां मुख्य रूप से दो कार्यों के साथ बनाई और संयोजित की जाती हैं:
(>>=) :: IO a -> (a -> IO b) -> IO b
यह फ़ंक्शन (जिसे आमतौर पर बाइंड कहा जाता है ) एक IO
एक्शन लेता है और एक फ़ंक्शन जो IO
एक्शन देता है, और IO
एक्शन उत्पन्न करता है, जो फ़ंक्शन को पहले IO
एक्शन द्वारा उत्पादित वैल्यू पर लागू करने का परिणाम है।
return :: a -> IO a
यह फ़ंक्शन कोई भी मूल्य लेता है (यानी, एक शुद्ध मूल्य) और IO अभिकलन लौटाता है जो कोई IO नहीं करता है और दिए गए मूल्य का उत्पादन करता है। दूसरे शब्दों में, यह एक नो-ओप I / O क्रिया है।
अतिरिक्त सामान्य कार्य हैं जो अक्सर उपयोग किए जाते हैं, लेकिन सभी ऊपर दिए गए दो के संदर्भ में लिखे जा सकते हैं। उदाहरण के लिए, (>>) :: IO a -> IO b -> IO b
(>>=)
समान है, लेकिन पहली क्रिया के परिणाम को नजरअंदाज किया जाता है।
इन कार्यों का उपयोग कर उपयोगकर्ता को बधाई देने वाला एक सरल कार्यक्रम:
main :: IO ()
main =
putStrLn "What is your name?" >>
getLine >>= \name ->
putStrLn ("Hello " ++ name ++ "!")
यह प्रोग्राम putStrLn :: String -> IO ()
और getLine :: IO String
का भी उपयोग करता है।
नोट: ऊपर दिए गए कुछ प्रकार के कार्य वास्तव में दिए गए प्रकारों से अधिक सामान्य हैं (अर्थात् >>=
, >>
और return
)।
IO शब्दार्थ
हास्केल में IO
प्रकार का बहुत ही समानार्थक प्रोग्रामिंग भाषाओं के समान है। उदाहरण के लिए, जब कोई s1 ; s2
लिखता है s1 ; s2
एक अनिवार्य भाषा में s1
को निष्पादित करने के लिए संकेत करता है, फिर कथन s2
, कोई हास्केल में समान चीज़ को मॉडल करने के लिए s1 >> s2
लिख सकता है।
हालांकि, IO
के शब्दार्थ एक अनिवार्य पृष्ठभूमि से आने की उम्मीद से थोड़ा हटते हैं। return
फ़ंक्शन नियंत्रण प्रवाह को बाधित नहीं करता है - कार्यक्रम पर इसका कोई प्रभाव नहीं पड़ता है अगर एक और IO
कार्रवाई अनुक्रम में चलती है। उदाहरण के लिए, मानक आउटपुट में return () >> putStrLn "boom"
सही ढंग से "बूम" प्रिंट करता है।
IO
का औपचारिक शब्दार्थ पिछले भाग में कार्यों को शामिल करने वाली सरल समानता के संदर्भ में दिया जा सकता है:
return x >>= f ≡ f x, ∀ f x
y >>= return ≡ return y, ∀ y
(m >>= f) >>= g ≡ m >>= (\x -> (f x >>= g)), ∀ m f g
इन कानूनों को आम तौर पर क्रमशः बाएं पहचान, सही पहचान और रचना के रूप में संदर्भित किया जाता है। उन्हें फ़ंक्शन के संदर्भ में अधिक स्वाभाविक रूप से कहा जा सकता है
(>=>) :: (a -> IO b) -> (b -> IO c) -> a -> IO c
(f >=> g) x = (f x) >>= g
निम्नलिखित नुसार:
return >=> f ≡ f, ∀ f
f >=> return ≡ f, ∀ f
(f >=> g) >=> h ≡ f >=> (g >=> h), ∀ f g h
आलसी IO
I / O अभिकलन निष्पादित करने वाले कार्य आम तौर पर सख्त होते हैं, जिसका अर्थ है कि क्रियाओं के अनुक्रम में सभी पूर्ववर्ती क्रियाएं अगली कार्रवाई शुरू होने से पहले पूरी होनी चाहिए। आमतौर पर यह उपयोगी और अपेक्षित व्यवहार है - putStrLn "X" >> putStrLn "Y"
को "XY" प्रिंट करना चाहिए। हालाँकि, कुछ लाइब्रेरी फ़ंक्शंस I / O आलसी प्रदर्शन करते हैं, जिसका अर्थ है कि मूल्य का उत्पादन करने के लिए आवश्यक I / O क्रिया केवल तब की जाती हैं जब मूल्य वास्तव में खपत होता है। ऐसे कार्यों के उदाहरण getContents
और readFile
। आलसी I / O एक हास्केल कार्यक्रम के प्रदर्शन को काफी कम कर सकता है, इसलिए पुस्तकालय कार्यों का उपयोग करते समय, ध्यान दिया जाना चाहिए कि कौन से कार्य आलसी हैं।
आईओ और do
अंकन
हास्केल विभिन्न IO मूल्यों को बड़े IO मूल्यों में संयोजित करने की एक सरल विधि प्रदान करता है। इस विशेष सिंटैक्स को * नोटेशन * के रूप में जाना जाता do
और यह केवल >>=
, >>
और return
फ़ंक्शंस के उपयोग के लिए सिंटैक्टिक शुगर है।
पिछले भाग में प्रोग्राम को नोटेशन का उपयोग do
हुए दो अलग-अलग तरीकों से लिखा जा सकता है, पहला लेआउट-सेंसिटिव और दूसरा लाइन्स सेंसर हो सकता है:
main = do
putStrLn "What is your name?"
name <- getLine
putStrLn ("Hello " ++ name ++ "!")
main = do {
putStrLn "What is your name?" ;
name <- getLine ;
putStrLn ("Hello " ++ name ++ "!")
}
सभी तीन कार्यक्रम बिल्कुल बराबर हैं।
* ध्यान दें कि do
टिप्पणी को monads बुलाया प्रकार निर्माताओं की एक व्यापक वर्ग के लिए लागू है।
"IO a" से 'a' प्राप्त करना
एक आम सवाल है "मैं का मान होना IO a
है, लेकिन मुझे लगता है कि करने के लिए कुछ करना चाहता हूँ a
मूल्य:? मैं इसे कैसे करने के लिए उपयोग मिलता है" बाहरी दुनिया से आए डेटा पर कोई कैसे काम कर सकता है (उदाहरण के लिए, उपयोगकर्ता द्वारा टाइप किया गया नंबर बढ़ाना)?
मुद्दा यह है कि यदि आप स्पष्ट रूप से प्राप्त डेटा पर शुद्ध फ़ंक्शन का उपयोग करते हैं, तो परिणाम अभी भी अशुद्ध है। यह इस बात पर निर्भर करता है कि उपयोगकर्ता ने क्या किया! के प्रकार के एक मूल्य IO a
एक "पक्ष प्रभावशाली गणना प्रकार के एक मूल्य में जिसके परिणामस्वरूप के लिए खड़ा है a
" जो केवल (क) में यह रचना द्वारा चलाया जा सकता है main
अपने कार्यक्रम और (ख) के संकलन और क्रियान्वित। इस कारण से, वहाँ शुद्ध हास्केल दुनिया के भीतर कोई रास्ता नहीं "प्राप्त करने के लिए है a
बाहर"।
इसके बजाय, हम एक नई संगणना, एक नया IO
मान बनाना चाहते हैं, जो रनटाइम पर a
मान का उपयोग करता है । यह IO
मानों की रचना का एक और तरीका है और इसलिए फिर से हम do
-notation का उपयोग कर सकते हैं:
-- assuming
myComputation :: IO Int
getMessage :: Int -> String
getMessage int = "My computation resulted in: " ++ show int
newComputation :: IO ()
newComputation = do
int <- myComputation -- we "bind" the result of myComputation to a name, 'int'
putStrLn $ getMessage int -- 'int' holds a value of type Int
यहां हम एक शुद्ध फ़ंक्शन ( getMessage
) का उपयोग करके एक String
को Int
में बदल देते हैं, लेकिन हम इसका उपयोग तब (जब) उस गणना के चलने के बाद IO
अभिकलन myComputation
के परिणाम पर लागू करने के do
नोटेशन का उपयोग कर रहे हैं। परिणाम एक बड़ा IO
अभिकलन, newComputation
। अशुद्ध संदर्भ में शुद्ध कार्यों का उपयोग करने की इस तकनीक को उठाने कहा जाता है।
लिखने के लिए stdout
हास्केल 2010 भाषा विशिष्टता के अनुसार निम्नलिखित प्रस्तावना में मानक IO फ़ंक्शन उपलब्ध हैं, इसलिए इनका उपयोग करने के लिए किसी भी आयात की आवश्यकता नहीं है।
putChar :: Char -> IO ()
- stdout
को एक char
लिखता है
Prelude> putChar 'a'
aPrelude> -- Note, no new line
putStr :: String -> IO ()
- एक String
को stdout
लिखता है
Prelude> putStr "This is a string!"
This is a string!Prelude> -- Note, no new line
putStrLn :: String -> IO ()
- एक String
को stdout
लिखता है और एक नई लाइन जोड़ता है
Prelude> putStrLn "Hi there, this is another String!"
Hi there, this is another String!
print :: Show a => a -> IO ()
- Show
एक उदाहरण के लिए stdout
लिखता a
Prelude> print "hi"
"hi"
Prelude> print 1
1
Prelude> print 'a'
'a'
Prelude> print (Just 'a') -- Maybe is an instance of the `Show` type class
Just 'a'
Prelude> print Nothing
Nothing
याद रखें कि आप deriving
का उपयोग करके अपने स्वयं के प्रकारों के लिए Show
को तत्काल कर सकते हैं:
-- In ex.hs
data Person = Person { name :: String } deriving Show
main = print (Person "Alex") -- Person is an instance of `Show`, thanks to `deriving`
GHCi में लोड हो रहा है और चल रहा है:
Prelude> :load ex.hs
[1 of 1] Compiling ex ( ex.hs, interpreted )
Ok, modules loaded: ex.
*Main> main -- from ex.hs
Person {name = "Alex"}
*Main>
`स्टडिन` से पढ़ना
हास्केल 2010 लैंग्वेज स्पेसिफिकेशन के अनुसार , निम्नलिखित प्रस्तावना में मानक IO फ़ंक्शन उपलब्ध हैं, इसलिए इनका उपयोग करने के लिए किसी भी आयात की आवश्यकता नहीं है।
getChar :: IO Char
- एक पढ़ा Char
से stdin
-- MyChar.hs
main = do
myChar <- getChar
print myChar
-- In your shell
runhaskell MyChar.hs
a -- you enter a and press enter
'a' -- the program prints 'a'
getLine :: IO String
- एक पढ़ा String
से stdin
, बिना नई लाइन चरित्र
Prelude> getLine
Hello there! -- user enters some text and presses enter
"Hello there!"
read :: Read a => String -> a
- read :: Read a => String -> a
- एक स्ट्रिंग को एक मान में बदलें
Prelude> read "1" :: Int
1
Prelude> read "1" :: Float
1.0
Prelude> read "True" :: Bool
True
अन्य, कम सामान्य कार्य हैं:
-
getContents :: IO String
- सभी उपयोगकर्ता इनपुट को एक स्ट्रिंग के रूप में लौटाता है, जिसे आवश्यकता के रूप में lazily पढ़ा जाता है -
interact :: (String -> String) -> IO ()
- स्ट्रिंग के प्रकार का एक कार्य लेता है-> स्ट्रिंग अपने तर्क के रूप में। मानक इनपुट डिवाइस से पूरे इनपुट को इस फ़ंक्शन को इसके तर्क के रूप में पारित किया जाता है