हास्केल में टूर्नामेंट समस्याओं का समाधान

सभी हब्बरहिती को शुभ दिन
यहाँ एक नहीं बल्कि प्रसिद्ध हास्केल भाषा के बारे में एक लेख है। इसमें, मैं हास्केल में एक साधारण टूर्नामेंट समस्या को हल करने का एक उदाहरण दिखाना चाहता हूं। मुझे उम्मीद है कि यह लेख शुरुआत करने वाले Haskell प्रोग्रामर को पूरा कार्यक्रम लिखने की दिशा में पहला कदम उठाने में मदद करता है।



एक कार्यक्रम के एक उदाहरण के रूप में, मैंने कोडफोर्सेस वेबसाइट से एक कार्य चुना। यह कार्य बहुत सरल है, जिसका अर्थ है कि हम सीधे उस भाषा पर ध्यान केंद्रित कर सकते हैं जिसे हम सीखना चाहते हैं, इसके अलावा, कोडफोर्सेस हास्केल में समाधान भेजने का समर्थन करता है, जिसका अर्थ है कि हम उनके परीक्षणों पर अपने समाधान का परीक्षण कर सकते हैं। आइए समस्या की स्थिति को पढ़कर शुरू करें।

दो नंबर दिए गए हैं। जब तक दोनों शून्य से अधिक नहीं हो जाते, तब तक वे उनके साथ एक ही ऑपरेशन करते हैं: छोटे को बड़ी संख्या से घटाया जाता है। यदि संख्याएं समान हैं, तो दूसरे को दूसरे से घटाया जाता है। उदाहरण के लिए, एक जोड़ी (4.13) एक ऑपरेशन में एक जोड़ी (4.17) से प्राप्त की जाती है, और एक जोड़ी (5.5) से एक जोड़ी (0.5)।

आपको एक निश्चित संख्या में जोड़े (एक i , b i ) दिए जाते हैं। उनमें से प्रत्येक के लिए कितने ऑपरेशन किए जाएंगे?


इसलिए, हमें परिणाम प्राप्त करने के लिए उन पर परिचालन की संख्या की गणना करने के लिए प्रत्येक जोड़ी की संख्या की आवश्यकता है। यह निम्नलिखित फ़ंक्शन हस्ताक्षर से मेल खाती है
solve :: Int -> Int -> Int solve = undefined 

मैंने फ़ंक्शन के कार्यान्वयन को अपरिभाषित के रूप में दर्ज किया, जो मुझे संकलन त्रुटियों के लिए कार्यक्रम की जांच करने की अनुमति देता है। मैं एक अभ्यास के रूप में पाठकों को फ़ंक्शन का पूर्ण कार्यान्वयन छोड़ देता हूं।

हमारे कार्यक्रम को इनपुट पढ़ना चाहिए। पहली पंक्ति में एक नंबर n होता है, जो उन संख्याओं के जोड़े को निर्दिष्ट करता है जिनके लिए आपको उत्तर प्रदर्शित करने की आवश्यकता होती है (हल फ़ंक्शन के मूल्य की गणना करें)। रीडिंग संख्याओं को निम्नानुसार लागू किया जा सकता है
 main = do nStr <- getLine let n = (read nStr :: Int) 

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

अगला, आपको एन लाइनें पढ़ने की आवश्यकता है, जिनमें से प्रत्येक में संख्याओं की एक जोड़ी है, जिसके लिए आपको हल फ़ंक्शन के मूल्य को प्रदर्शित करने की आवश्यकता है। यहां एक क्रिया को दोहराना आवश्यक है (एक पंक्ति में 2 संख्याएं गिनें, हल फ़ंक्शन के मूल्य की गणना करें, परिणाम प्रिंट करें) एन बार। सबसे पहले, हम इस कार्रवाई को लागू करते हैं
 printSolution :: IO () printSolution = do numsStr <- getLine let nums = map (read :: String -> Int) $ words numsStr print $ solve (nums!!0) (nums!!1) 

@leventov ने पैटर्न मिलान का उपयोग करके संख्याओं को पढ़ने का एक अच्छा तरीका सुझाया
 printSolution :: IO () printSolution = do numsStr <- getLine let [n1, n2] = map read $ words numsStr print $ solve n1 n2 

ध्यान दें कि मैंने यहां स्पष्ट रूप से पढ़ने के प्रकार को निर्दिष्ट नहीं किया है। हास्केल प्रकार प्रणाली इसे स्वयं आउटपुट करने में सक्षम होगी, क्योंकि हल फ़ंक्शन इंट के मापदंडों को स्वीकार करता है, इसलिए यह कोड को अव्यवस्थित करने के लिए बहुत अधिक मतलब नहीं है (धन्यवाद dima_mendeleev )।

फ़ंक्शन लाइन (गेटलाइन) को पढ़ता है, इसे भागों (शब्दों) में विभाजित करता है, प्रत्येक भाग को एक नंबर (मानचित्र (पढ़ें :: स्ट्रिंग -> इंट)) में परिवर्तित करता है, और फिर रीड पैरामीटर (प्रिंट $ हल (अंक) के साथ हल किए गए फ़ंक्शन के मूल्य को प्रिंट करता है !! ०) (अंक !! १))। मैं शब्दों को याद रखने और कार्यों को पढ़ने की सलाह देता हूं, वे इनपुट के साथ काम करने के लिए उपयोग करने के लिए बहुत सुविधाजनक हैं, और वास्तव में तार के साथ।

फिर आपको इस क्रिया के दोहराव को एन बार लागू करने की आवश्यकता है। अनिवार्य भाषाओं में, यह एक लूप के माध्यम से लिखा जाएगा, लेकिन हमारे पास एक कार्यात्मक भाषा है, इसलिए हम पुनरावृत्ति का सहारा लेंगे
 printNSolutions :: Int -> IO () printNSolutions 1 = printSolution printNSolutions n = do printSolution printNSolutions (n-1) 

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

जो कुछ भी किया जाना बाकी है वह फ़ंक्शन `printNSolutions` को तर्क एन के साथ पहले से ही मुख्य फ़ंक्शन में पहले से पढ़ा जाता है
 main = do nStr <- getLine let n = (read nStr :: Int) printNSolutions n 

अब मुख्य फ़ंक्शन को अंत में जोड़ा गया है, हालांकि, आप इसे थोड़ा छोटा कर सकते हैं (और फिर से, रीड फ़ंक्शन का प्रकार स्पष्ट रूप से छोड़ा जा सकता है)
 main = do nStr <- getLine printNSolutions $ read nStr 

या करना-संकेतन को बिलकुल छोड़ देना
 main = getLine >>= (printNSolutions . read) 


बस इतना ही, हमने हास्केल में एक कार्यक्रम लिखा था! अंत में, मैं इसका पूरा कोड दूंगा (यदि आप अभ्यास करना चाहते हैं, तो सूची को न खोलें, बल्कि कार्यान्वयन को स्वयं लिखें और कोडफोर्स सिस्टम में इसका परीक्षण करें)
लिस्टिंग
 module Main where solve :: Int -> Int -> Int solve 0 _ = 0 solve _ 0 = 0 solve ab | a >= b = (a `div` b) + solve b (a `mod` b) | otherwise = solve ba printSolution :: IO () printSolution = do numsStr <- getLine let nums = map (read :: String -> Int) $ words numsStr print $ solve (nums!!0) (nums!!1) printNSolutions :: Int -> IO () printNSolutions 1 = printSolution printNSolutions n = do printSolution printNSolutions (n-1) main = do nStr <- getLine printNSolutions $ (read nStr :: Int) 

Source: https://habr.com/ru/post/In166763/


All Articles