2012-02-08 10 views
5

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

मैं एक ढेर जोड़ तोड़ के लिए कुछ कार्यों की स्थापना करना चाहते हैं:

type Stack = String 

pop :: Stack -> (Char,Stack) 
pop (x:xs) = (x,xs) 

push :: Char -> Stack -> ((),Stack) 
push a xs = ((),a:xs) 

बस इतना ही अच्छा है अगर मैं राज्य इकाई में काम कर रहा हूँ, लेकिन मैं StateT इकाई में काम कर रहा हूँ

balanced :: StateT Stack (State String) Bool 

मुझे पता है कि मुझे बताया गया है कि ढेर में डुप्लिकेट monads नहीं है। मैं इसे इस तरह से कर रहा हूं क्योंकि मुझे लगता है कि यह पुश और पॉप परिभाषाओं को कैसे सरल बनाता है।

दो समस्याओं:

  1. कोई फर्क नहीं पड़ता कि मुझे क्या करना मैं धक्का लागू करते हैं और ढेर StateT में निहित करने के लिए पॉप के लिए एक रास्ता नहीं मिल रहा।
  2. मुझे पता नहीं है कि कैसे मुख्य कार्य

यहाँ से कॉल करने के लिए कोड

next :: String -> (Maybe Char,String) 
next ""  = (Nothing,[]) 
next (x:xs) = (Just x,xs) 

balanced = do 
      c <- lift (state next) 
      case c of 
       Nothing -> return True 
       Just c -> if elem c open 
         then (push c) >> balanced 
         else if elem c close 
           then pop >>= \x -> 
           if eq x c 
           then balanced 
           else return False 
           else balanced 
      where open = "<{([" 
       close = "])}>" 
       eq '(' ')' = True 
       eq '{' '}' = True 
       eq '<' '>' = True 
       eq '[' ']' = True 
       eq _ _ = False 
+0

आंतरिक मोनड के लिए 'स्टेट स्ट्रिंग' के बजाय 'रीडर स्ट्रिंग' का उपयोग करने का प्रयास करें। – dflemstr

उत्तर

7

आपकी समस्या यह है कि आपके push और pop सिर्फ साधारण हैं के बाकी है, गैर monadic समारोह जिसे आप monadic do-block में उपयोग करने का प्रयास कर रहे हैं। आप next का उपयोग कर रहे हैं, क्योंकि आप इसे state फ़ंक्शन का उपयोग करके कॉल करते हैं, लेकिन जैसा कि आपने शायद देखा है, state केवल सादा State मोनैड के लिए काम करता है और StateT नहीं।

हम इस तरह state की एक इकाई ट्रांसफार्मर संस्करण को लागू कर सकते हैं:

stateT :: Monad m => (s -> (a, s)) -> StateT s m a 
stateT f = do 
    (x, s') <- gets f 
    put s' 
    return x 

और फिर push और pop साथ balanced समारोह में इसका इस्तेमाल करते हैं।

balanced :: StateT Stack (State String) Bool 
balanced = do 
      c <- lift (state next) 
      case c of 
       Nothing -> return True 
       Just c -> if elem c open 
         then (stateT $ push c) >> balanced 
         else if elem c close 
           then stateT pop >>= \x -> 
           if eq x c 
            then balanced 
            else return False 
           else balanced 
      where open = "<{([" 
       close = "])}>" 
       eq '(' ')' = True 
       eq '{' '}' = True 
       eq '<' '>' = True 
       eq '[' ']' = True 
       eq _ _ = False 

समारोह इस तरह कहा जाता है:

evalState (evalStateT balanced []) s 

कहाँ s प्रारंभिक स्ट्रिंग है और [] प्रारंभिक ढेर है।

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