2012-02-01 12 views
6

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

मैंने इसे monads के साथ करने की कोशिश की है और यह सिर्फ एक साथ फिट नहीं है। मैंने सभी अलग-अलग राज्य घटकों को एक प्रकार के रूप में इलाज करने की कोशिश की, लेकिन इससे मुझे मूल्य बनाने की समस्या के साथ छोड़ दिया गया।

State Program() -- Represents the state of the processor after a single iteration of the fetch execute cycle 

एकमात्र ऐसा तरीका था जिसने कोई अर्थ बनाया। लेकिन उस बिंदु पर भी परेशान क्यों? मैं स्ट्रिंग मेरी समग्र प्रकार से बाहर खींच रहा है और मूल्य

State Program' String 

जो महान काम किया, तथ्य यह है कि मैं चल रहा है उत्पादन की जरूरत के लिए छोड़कर रूप में यह इलाज से यह टूट की कोशिश की। कोई फर्क नहीं पड़ता कि मैंने क्या किया था मैं एक ही समय में स्ट्रिंग और राज्य दोनों को पकड़ नहीं सकता था।

अब मैं मोनड ट्रांसफार्मर के साथ जुड़ने की कोशिश कर रहा हूं। ऐसा लगता है कि मुझे राज्य के सभी अलग-अलग स्तरों को अलग करना है। लेकिन मेरा सिर तेजी से विस्फोट कर रहा है।

StateT Registers (StateT Memory (State Output)) a = 
StateT (registers -> (StateT Memory (State Output)) (a,registers)) 

StateT Registers (StateT Memory (State Output)) a = 
StateT (registers -> (Memory -> (Output -> (((a,Registers),Memory),Output)))) 

मैंने अभी तक एफईसायकल काउंटर में भी नहीं रखा है!

सवाल: सही रास्ते पर

  1. एम आई?
  2. देखकर कि मैं अब मोनैड ट्रांसफार्मर खींच रहा हूं, क्या यह "आउटपुट आउटपुट" को राज्य के रूप में इलाज करना बंद करना संभव है और इसे आईओ मोनड पर बंद कर दें? यह शानदार होगा, इसे पकड़ने के बजाय मैं इसे प्रिंट कर सकता था।
  3. मुझे राज्य को कितनी परतों को अलग करना चाहिए? मैं दो अलग-अलग परतों को देख सकता हूं, लेकिन वे एक दूसरे पर बारीकी से निर्भर करते हैं (स्मृति और रजिस्ट्रार दोनों स्मृति और रजिस्टरों दोनों की स्थिति पर निर्भर करते हैं)। क्या मुझे उन्हें एक ही राज्य के रूप में एक साथ रखना चाहिए या उन्हें अलग करना चाहिए और उन्हें ढेर करना चाहिए? कौन सा दृष्टिकोण सबसे पठनीय कोड का उत्पादन करेगा?
+1

शायद "चल उत्पादन" सबसे अच्छा लेखक इकाई (http://monads.haskell.cz/html/writermonad.html देखें) का उपयोग प्रतिनिधित्व किया जा सकता है? –

उत्तर

9

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

इसके बजाय, मैं StateT Program IO() सुझाव है। राज्य के लिए इंटरफ़ेस वही है और जैसा कि आपने कहा था, आप IO में liftIO का उपयोग कर आउटपुट कर सकते हैं। निश्चित रूप से, मान प्रकार () है, लेकिन इसके साथ क्या गलत है? शीर्ष-स्तरीय एमुलेटर से कोई प्रासंगिक मान नहीं है। और, ज़ाहिर है, आपके पास आपके एमुलेटर के भाग के रूप में छोटे, पुन: प्रयोज्य घटक होने की संभावना है, और उनके पास प्रासंगिक परिणाम प्रकार होंगे। (वास्तव में, get एक ऐसा घटक है।) शीर्ष स्तर पर कोई सार्थक वापसी मूल्य होने में कुछ भी गलत नहीं है।

जहां तक ​​आसानी से राज्य के प्रत्येक भाग तक पहुँचने, क्या आप देख रहे हैं लेंस है, this Stack Overflow answer एक उत्कृष्ट परिचय है। वे आपको अपने राज्य के स्वतंत्र हिस्सों को आसानी से और आसानी से एक्सेस और संशोधित करने देते हैं। उदाहरण के लिए, data-lens कार्यान्वयन के साथ, आप आसानी से regA, या stack %= drop 2 बढ़ाने के लिए ढेर के पहले दो तत्वों को दूर करने के regA += 1 की तरह कुछ लिख सकते हैं।

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

+0

यह खूनी भयानक है। टेम्पलेट हैकेल सीखने का समय। क्या rega + = 1 जैसी कार्यात्मक परिभाषा बैकिंग सामग्री ढूंढना अभी भी आसान है? क्योंकि यह अच्छा और पठनीय है और सबसे स्पष्ट रूप से (बहुत जरूरी) इरादा व्यक्त करता है, यह कार्यात्मक कोड की तरह कुछ नहीं दिखता है। – TheIronKnuckle

+1

डेटा-लेंस-टेम्पलेट का उपयोग करने के लिए आपको टेम्पलेट हास्केल सीखना नहीं है; बस अपनी फ़ाइल के शीर्ष पर '{- # LANGUAGE टेम्पलेट हास्केल # -} 'और' मेकलेन्स ['' प्रोग्राम] 'को' प्रोग्राम' की परिभाषा के नीचे कहीं भी चिपकाएं। जहां तक ​​'(+ =)' की परिभाषा है, निश्चित है; वे 'स्टेटटी' के लिए कोर लेंस एपीआई के बस साधारण रैपर हैं; [स्रोत] (http://hackage.haskell.org/packages/archive/data-lens/2.0.2/doc/html/src/Data-Lens-Strict.html) हैकेज दस्तावेज़ से जुड़ा हुआ है। – ehird

+2

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

2

यह करने के लिए एक डेटा प्रकार है कि रजिस्टर और स्मृति का प्रतिनिधित्व करता है बनाने के लिए किया जाएगा एक आसान तरीका:

data Register = ... 
data Memory = ... 
data Machine = Machine [Register] Memory 

तो कुछ कार्यों कि रजिस्टरों/स्मृति को अपडेट किया है। अब आप अपने प्रकार के लिए अपने राज्य के लिए इस प्रकार के और उत्पादन का उपयोग करें:

type Simulation = State Machine Output 

अब प्रत्येक आपरेशन के रूप में हो सकता है:

operation previous = do machine <- get 
         (result, newMachine) <- operate on machine 
         put newMachine 
         return result 

यहाँ previous मशीन के पिछले उत्पादन होता है। आप इसे परिणाम में भी शामिल कर सकते हैं।

तो Machine प्रकार मशीन की स्थिति का प्रतिनिधित्व करता है; आप इसके माध्यम से पिछले परिचालन के आउटपुट थ्रेड कर रहे हैं।

state threads (Control.Monad.ST) का उपयोग करने के लिए एक अधिक परिष्कृत तरीका होगा। ये आपको बाहर की गारंटी शुद्धता के दौरान एक समारोह के अंदर परिवर्तनीय संदर्भ और सरणी का उपयोग करने देते हैं।