2012-06-12 35 views
5

मेरे पास मॉड्यूल है जहां एक वैश्विक वातावरण (पड़ोसी आईपी पते आदि जैसी कुछ बाधाओं को परिभाषित करना) प्रारंभिक कार्य को कॉल करके बनाया और प्रारंभ किया गया है। बाद के कार्यों को इन बाधाओं का उपयोग करते समय इन बाधाओं का उपयोग करना चाहिए।वैश्विक चर और पाठक मोनैड

जबकि सिद्धांत रूप में मैं समझता हूं कि पाठक मोनाड क्या करता है मुझे पूरा यकीन नहीं है कि मैं इसे अपनी समस्या, एएसपी पर कैसे लागू कर सकता हूं।

  • उपयोगकर्ता द्वारा परिभाषित पर्यावरण को शुरू करने के लिए इसका उपयोग कैसे किया जा सकता है और प्रारंभिक कार्य में डेटा/तर्क के रूप में पारित किया जा सकता है। मेरा मतलब है, पाठक मोनद को वास्तविक मूल्य प्राप्त करना है जो कहीं से वैश्विक अपरिवर्तनीय वातावरण बनाते हैं। मैं चाहूँगा कि मूल्यों पाठक इकाई के माध्यम से myinitial :: arg1 -> arg1 -> IOString की तरह एक प्रारंभ करने समारोह कॉल जहां बाद में arg1 और arg2 वैश्विक बनने से बाद के कार्यों के लिए सुलभ अपरिवर्तनीय डेटा पढ़ा जाता है (?)

  • मैं समारोह तर्क के रूप में इन पर्यावरण मूल्यों कैसे उपयोग कर सकते हैं जैसे recvFrom s arg1 जहां arg1 मेरे पर्यावरण से वैश्विक अपरिवर्तनीय डेटा है। या if arg2 > arg1 then ... else ...

मैं निश्चित रूप से एक विन्यास फाइल कर सकता है, लेकिन मुझे लगता है कि एक विन्यास फाइल ज्यादा लचीलापन को दूर ले जाएगा।

[संपादित करें] मैं पूछने के बारे में समझता हूं, लेकिन अतिरिक्त "पॉइंटफ्री-जैसी" तरीके नहीं होनी चाहिए ताकि कार्य हस्ताक्षर को सही तरीके से परिभाषित किया गया हो तो वैश्विक/पर्यावरण अपरिवर्तनीय छोड़ा जा सकता है? this लागू करने के लिए मुझे या तो मुझे फिर से प्रतिक्रिया करने की आवश्यकता होगी।

उत्तर

4

यहां एक उदाहरण है जो चीजों को साफ़ कर सकता है।सबसे पहले आप रीडर मॉड्यूल आयात करने की आवश्यकता:

import Control.Monad.Reader 

अब हम कुछ डेटा संरचना को परिभाषित (है कि हम एक नाम और एक उम्र धारण करने के लिए उपयोग करने के लिए जा रहे हैं) जाने

data Config = Config { name :: String, age :: Int } 

अब एक समारोह को परिभाषित है कि रीडर मोनड में काम करता है (यह प्रकार Reader Config (String, Int) है लेकिन हमें इसे निर्दिष्ट करने की आवश्यकता नहीं है - इसे अनुमानित किया जा सकता है)। यह सब कार्य पर्यावरण के लिए पूछता है (टाइप Config) और फिर फ़ील्ड निकालता है और उनके साथ कुछ करता है।

example = do 
    c <- ask 
    return ("Hello " ++ name c, 2 * age c) 

अब हम इसे एक कार्यक्रम में एक साथ रख देते हैं। डू ब्लॉक के बाद पहली चार पंक्तियां उपयोगकर्ता को अपना नाम और उम्र दर्ज करने की अनुमति देती हैं। फिर हम उपयोगकर्ता के आदानों का उपयोग कर एक Config संरचना का निर्माण और यह पर्यावरण के साथ example निष्पादित, का उपयोग करते हुए (हम read उपयोग करने के लिए एक Int में चर _age है, जो एक String है, कन्वर्ट करने के लिए इतना है कि हम इसे Config निर्माता फ़ीड कर सकते हैं) runReader फ़ंक्शन। अंत में, हम कुछ आउटपुट उत्पन्न करने के लिए इस गणना के परिणाम का उपयोग करते हैं।

main = do 
    putStrLn "Enter your name:" 
    _name <- getLine 
    putStrLn "Enter your age:" 
    _age <- getLine 
    let config = Config _name (read _age) 
    let result = runReader example config 
    putStrLn $ fst result 
    putStrLn $ "Twice your age is: " ++ show (snd result) 
+0

आंशिक रूप से काम करता है, जैसा कि इस प्रश्न में उल्लिखित है कि मेरे पास ** मॉड्यूल ** है जिसमें कई कार्य हैं; उनमें से एक प्रारंभिक कार्य है जो पर्यावरण बनाता है। मॉड्यूल से कार्य जिन्हें बाद में कहा जाता है, पर्यावरण का उपयोग करना चाहिए। क्या पाठक मोनड के साथ यह संभव है? –

+0

लेकिन यह कैसे काम करना चाहिए? आपके/मेरे उदाहरण में प्रारंभकर्ता फ़ंक्शन कुछ कहता है जैसे 'config config = config blabla' और बाद के फ़ंक्शन को' परिणाम = runReader उदाहरण कॉन्फ़िगरेशन 'करने की आवश्यकता होगी; - हालांकि बाद के फ़ंक्शन को 'कॉन्फ़िगरेशन' नहीं पता है। –

+0

[यह जिस्ट] देखें (https://gist.github.com/2924160) जिसमें एक साधारण उदाहरण है। मॉड्यूल 1 में, हम एक ऐसे फ़ंक्शन को परिभाषित करते हैं जो वैश्विक वातावरण को प्रारंभ करता है, और कुछ ऐसे कार्य जो वैश्विक पर्यावरण पर निर्भर करते हैं। मॉड्यूल 2 में केवल एक मुख्य फ़ंक्शन होता है जो पर्यावरण को प्रारंभ करता है, और 'runReader' (** संपादित करें: ** माफ़ी,' का उपयोग करके उस पर निर्भर फ़ंक्शंस को कॉल करता है, मैंने उस मूल टिप्पणी को हटा दिया जिसे आपने उत्तर दिया और इसे इसके साथ बदल दिया।) –

5

ask और runReader फ़ंक्शंस के लिए प्रकार और दस्तावेज़ीकरण का निरीक्षण करके आपके अधिकांश प्रश्नों का उत्तर दिया जा सकता है।

पहले, ask:

ask :: Reader m r => m r 

यह अंतर्निहित केवल पढ़ने के लिए इकाई में लिपटे डेटा देता है।

do x <- ask 
    recvFrom s x 

(recvFrom के प्रकार पर निर्भर, निश्चित रूप से)

अगला है: कूल, कि इतने कैसे आप राज्य के लिए जब आप अन्य कार्यों के साथ इसका उपयोग करना चाहते ऊपर अपने उदाहरण में मिल जाएगा, है runReader, इस तरह आप इसे प्रारंभिक डेटा के बारे में बात कर रहे थे।

runReader :: Reader r a -> r -> a 

जिसका अर्थ है: प्रकार r की केवल पढ़ने के लिए डेटा के साथ गणना (पहला तर्क) (दूसरा तर्क) चलाने यह मूल रूप से सिर्फ Reader गणना डेटा यह दिया है का उपयोग कर चलाता है। यह अंत में 1 तर्क, a के परिणाम प्रकार को वापस कर देगा।

result = runReader computationUsingArg1Arg2 (arg1, arg2) 

फिर computationUsingArg1Arg2 अंदर आप arg1 और arg2ask के माध्यम से पढ़ सकते हैं: आपके मामले में, इस तरह लग सकता है।

+0

धन्यवाद, मैं अभी भी समझ नहीं पा रहा हूं कि मेरे उदाहरण में 'runReader' को कैसे लागू किया जाए, मेरे प्रश्न में से एक बुलेट। –

+0

मैंने थोड़ा जवाब दिया है, मुझे बताएं कि क्या अभी भी कुछ स्पष्ट नहीं है। – ScottWest

+0

मुझे पता है कि यह एक साल बाद है लेकिन मेरे लिए यह सवाल का जवाब नहीं देता है। समस्या यह नहीं है कि compuationUsingArg1Arg2 है, लेकिन यह computationUsingArg1Arg2 अन्य कार्यों को कॉल करने में सक्षम होना चाह सकता है जिन्हें "वैश्विक" जानकारी तक पहुंच की भी आवश्यकता है। अन्यथा आप सीधे पैरामीटर पास कर सकते हैं और पाठक की आवश्यकता नहीं है। तो उन सभी अन्य कार्यों को कैसे परिभाषित और बुलाया जाता है? – David

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