2012-11-11 20 views
7

के रूप में कछुए ग्राफिक्स मैं हास्केल में turtle graphics को लागू करने की कोशिश कर रहा हूं। लक्ष्य इस तरह एक समारोह में लिखने के लिए सक्षम होने के लिए है:हार्सेल मोनाड

draw_something = do 
    forward 100 
    right 90 
    forward 100 
    ... 

और फिर इसे अंक (शायद अतिरिक्त गुणों के साथ) की एक सूची तैयार की है:

> draw_something (0,0) 0  -- start at (0,0) facing east (0 degrees) 
[(0,0), (0,100), (-100,100), ...] 

मैं एक में सभी इस काम कर रहे है 'सामान्य' तरीका है, लेकिन मैं इसे हास्केल मोनाड के रूप में लागू करने में विफल रहा हूं और डू-नोटेशन का उपयोग करता हूं। बुनियादी कोड:

data State a = State (a, a) a -- (x,y), angle 
    deriving (Show, Eq) 

initstate :: State Float 
initstate = State (0.0,0.0) 0.0 


-- constrain angles to 0 to 2*pi 
fmod :: Float -> Float 
fmod a 
    | a >= 2*pi = fmod (a-2*pi) 
    | a < 0 = fmod (a+2*pi) 
    | otherwise = a 

forward :: Float -> State Float -> [State Float] 
forward d (State (x,y) angle) = [State (x + d * (sin angle), y + d * (cos angle)) angle] 

right :: Float -> State Float -> [State Float] 
right d (State pos angle) = [State pos (fmod (angle+d))] 


bind :: [State a] -> (State a -> [State a]) -> [State a] 
bind xs f = xs ++ (f (head $ reverse xs)) 

ret :: State a -> [State a] 
ret x = [x] 
इस के साथ

अब मैं लिख सकते हैं

> [initstate] `bind` (forward 100) `bind` (right (pi/2)) `bind` (forward 100) 
[State (0.0,0.0) 0.0,State (0.0,100.0) 0.0,State (0.0,100.0) 1.5707964,State (100.0,99.99999) 1.5707964] 

और अपेक्षित परिणाम मिलता है। हालांकि मैं इसे Monad का उदाहरण नहीं बना सकता।

`State' is not applied to enough type arguments 
Expected kind `*', but `State' has kind `* -> *' 
In the instance declaration for `Monad [State]' 

में

instance Monad [State] where 
    ... 

परिणाम और अगर मैं एक नई वस्तु में सूची लपेट

data StateList a = StateList [State a] 

instance Monad StateList where 
    return x = StateList [x] 

मैं

Couldn't match type `a' with `State a' 
     `a' is a rigid type variable bound by 
     the type signature for return :: a -> StateList a 
      at logo.hs:38:9 
    In the expression: x   
    In the first argument of `StateList', namely `[x]' 
    In the expression: StateList [x] 

मैं विभिन्न अन्य संस्करणों, लेकिन मैं कभी नहीं की कोशिश की मिल जैसा कि मैं चाहता हूं इसे चलाने के लिए मिला। मैं क्या गलत कर रहा हूं? मैं गलत तरीके से क्या समझूं?

+0

कछुए की स्थिति और शीर्षकों का इतिहास बढ़ाना, एक टर्टग्राफिक्स मोनैड को लागू करना संभव होना चाहिए। लेकिन जिस तरह से आप 'मोनाड' इंस्टेंस को लागू करने की कोशिश कर रहे हैं, इस प्रकार के मानों को आम तौर पर मूल्यों के प्रकारों के साथ प्रदर्शित करने के लिए उपयोग किए जाने वाले प्रकार को भ्रमित करता है। आपकी 'ret' और 'bind' चिंता गणना जो केवल मानों के रूप में मानती हैं। लेकिन 'वापसी' और '>> = 'को किसी भी प्रकार के मूल्यों से संबंधित गणनाओं को व्यवस्थित करने के तरीके को समझाया जाना चाहिए, जिनमें से कुछ कछुए के निशान को भी बढ़ा सकते हैं। – pigworker

+0

यदि आप अंक की सूची उत्पन्न करने के लिए "मोनैड" चाहते हैं तो आप राज्य के बजाय लेखक + राज्य चाहते हैं। लेखक आमतौर पर "संचय का मोन" होता है हालांकि यह अन्य तरीकों से काम कर सकता है। प्रगति के लिए आपको यह देखने की भी आवश्यकता है कि क्यों राज्य मोनैड 'न्यूटाइप' द्वारा लिपटे कार्यों को फेंकते हैं - वे मौजूदा राज्य से नए राज्य के साथ-साथ नए राज्य और उत्तर की एक जोड़ी हैं, न केवल नए राज्य। अक्सर जवाब 'इकाई' उर्फ ​​() है। उदाहरण आगे आमतौर पर 'आगे :: फ्लोट -> कछुए() 'टर्टल नामक एक मोनैड मानते हैं। –

उत्तर

6

आपके द्वारा तैयार किए जा रहे मोनैड में दो प्रकार के पैरामीटर होने की आवश्यकता है। सहेजे गए निशान के लिए एक (जिसे एक विशेष do अनुक्रम के लिए तय किया जाएगा) और अन्य गणना के परिणामों के लिए।

आपको दो कछुए-मोनैडिक मानों को कैसे लिखना है, इस बारे में भी सोचने की आवश्यकता है ताकि बाइंडिंग ऑपरेशन सहयोगी हो। उदाहरण के लिए,

right 90 >> (right 90 >> forward 100) 

(right 90 >> right 90) >> forward 100 

(और निश्चित रूप से >>= आदि के लिए इसी तरह) के बराबर होना चाहिए। इसका अर्थ यह है कि यदि आप बिंदुओं की सूची से कछुए के इतिहास का प्रतिनिधित्व करते हैं, तो बाध्यकारी संचालन सबसे अधिक संभावना है कि अंक की सूचियों को एक साथ जोड़ना न हो; forward 100 अकेले कुछ [(0,0),(100,0)] जैसे परिणामस्वरूप होगा, लेकिन जब यह रोटेशन के साथ प्रीपेड किया जाता है, तो सहेजे गए बिंदुओं को भी घूर्णन करने की आवश्यकता होती है।


मैं कहना चाहता हूँ कि सबसे सरल दृष्टिकोण Writer इकाई का उपयोग करने के लिए होगा। लेकिन मैं अंक को नहीं बचाऊंगा, मैं कछुए के कार्यों को केवल सहेजता हूं (ताकि मूल्यों को संयोजित करते समय हमें बिंदुओं को घुमाने की आवश्यकता न हो)। जैसे

data Action = Rotate Double | Forward Double 

type TurtleMonad a = Writer [Action] a 

कुछ फिर अपने कार्यों में से प्रत्येक बस Writer में अपने तर्क लिखते हैं (यह भी है कि हम वर्तमान दिशा को ट्रैक करने की जरूरत नहीं है, यह कार्रवाई में निहित है। इसका मतलब है)।और अंत में, आप इसे से अंतिम सूची निकालने और एक साधारण समारोह है कि अंक की एक सूची में सभी कार्यों धर्मान्तरित कर सकते हैं:

track :: [Action] -> [(Double,Double)] 

अद्यतन: उपयोग करने के लिए इसके बजाय [Action] का उपयोग करने का यह बेहतर होगा Data.Sequence से Seq। यह भी एक monoid है और concatenating two sequences बहुत तेजी से है, यह परिशोधित है जटिलता हे (लॉग (न्यूनतम (n1, एन 2))), ओ (n1) की तुलना में (++) की है। तो बेहतर प्रकार

type TurtleMonad a = Writer (Seq Action) a 
संबंधित मुद्दे