2010-05-16 13 views
7

आउटपुट पर एकाधिक कॉल कैसे जारी कर सकता है जब तक कि आउटपुट SDL.NoEvent न हो और सभी परिणामों को एक सूची में एकत्र करें?सूची में आईओ आउटपुट एकत्रित करना

जरूरी संदर्भ में कुछ इस तरह:

events = [] 
event = SDL.pollEvent 
while (event != SDL.NoEvent) { 
     events.add(event) 
     event = SDL.pollEvent 
} 

उत्तर

4

जेम्स कुक इसलिए इस समारोह के साथ monad-loop रों विस्तार करने के लिए तरह था:

events <- unfoldWhileM (/= SDL.NoEvent) SDL.pollEvent 
2

आप monadic सूचियों का उपयोग कर सकते हैं:

import Control.Monad.ListT (ListT) 
import Control.Monad.Trans.Class (lift) -- transformers, not mtl 
import Data.List.Class (takeWhile, repeat, toList) 
import Prelude hiding (takeWhile, repeat) 

getEvents :: IO [Event] 
getEvents = 
    toList . takeWhile (/= NoEvent) $ do 
     repeat() 
     lift pollEvent :: ListT IO Event 

hackage पर "सूची" पैकेज से ListT

 
takeWhileM :: (a -> Bool) -> IO a -> IO [a] 
takeWhileM p act = do 
    x <- act 
    if p x 
    then do 
     xs <- takeWhileM p act 
     return (x : xs) 
    else 
     return [] 
के बजाय

:

do 
    xs <- takeWhileM p act 
    return (x : xs) 

आप भी उपयोग कर सकते हैं:

liftM (x:) (takeWhileM p act) उपज:

 
takeWhileM :: (a -> Bool) -> IO a -> IO [a] 
takeWhileM p act = do 
    x <- act 
    if p x 
    then liftM (x:) (takeWhileM p act) 
    else return [] 

तो आप उपयोग कर सकते

+0

क्यों "दोहराने()":

unfoldWhileM :: Monad m => (a -> Bool) -> m a -> m [a] 

एसडीएल के साथ प्रयोग किया? – Peaker

+1

@peaker: 'repeat() :: ListT IO()' एक अनंत आईओ-मोनैडिक सूची है जिसमें मूल्य हैं ('()')। तो हम '(>>) 'इसे' लिफ्ट पोलवेन्ट 'के साथ रखते हैं ताकि अनंत सूची के प्रत्येक तत्व के लिए हम' pollEvent' 'कर सकें। 'टेकवाइली' इसे एक सीमित monadic सूची बनाता है और फिर 'toList' इसे बनाता है' :: आईओ [घटना] '। – yairchu

+0

यह थोड़ा अजीब लगता है .. शायद "repeatM (लिफ्ट pollEvent)" जैसे कुछ का उपयोग करने के लिए और अधिक समझ में आता है? – Peaker

4

आप की तरह कुछ इस्तेमाल कर सकते हैं : takeWhileM (/=SDL.NoEvent) SDL.pollEvent

+0

में होगा, मैं सुझाव दूंगा कि 'टेकयूनीटएम :: मोनाड एम => (ए -> बूल) -> एम -> एम [ए] '(के साथ जानकारी हानि (विशेष रूप से आईओ monads से) से बचने के लिए उपयुक्त 'वापसी [x] 'जब' px' 'false' है)। यह सामान्य लग सकता है जब यह केवल 'एसडीएल.एंडवेन्ट' है लेकिन यह 'वाम "सिस्टम क्रैश के लिए गलत हो सकता है" :: या तो स्ट्रिंग ए'। – ony

+0

ओह, और आप शायद आलसी सूची बनाना चाहते हैं, इसलिए 'System.Unsafe' (या ऐसा कुछ) से' interleaveIO' का उपयोग करने की आवश्यकता है। अर्थात। 'लिफ्टएम (एक्स :) (इंटरलेवियो (unsafeTakeUntilM पी एक्ट) जैसे कुछ '' – ony

+1

' टेकवॉल्डएम 'के कई प्रकार: http://stackoverflow.com/questions/1133800/haskell-monadic-takewhile/1138153#1138153 – kennytm

0

मैं अंत में btw अपने जवाब के लिए hackage

getEvents :: IO Event -> [Event] -> IO [Event] 
getEvents pEvent es = do 
    e <- pEvent 
    let hasEvent = e /= NoEvent 
    if hasEvent 
    then getEvents pEvent (e:es) 
    else return (reverse es) 

धन्यवाद से एक वास्तविक एसडीएल खेल में इस कोड स्निपेट से अधिक ठोकर खाई!

+1

यदि एसडीएल एपीआई इसे सीधे प्रदान नहीं करता है, तो एक शॉट में कतार में प्रतीक्षा करने वाली सभी घटनाओं को खींचने के लिए यह इतना लोकप्रिय तरीका है? इससे कुछ सिंक से बचने में मदद मिल सकती है। थ्रेड-सुरक्षित कतार के लिए ओवरहेड। – ony

1

इस GHCi सत्र Event के लिए इन स्टब्स और pollEvent

data Event = NoEvent | SomeEvent 
    deriving (Show,Eq) 

instance Random Event where 
    randomIO = randomRIO (0,1) >>= return . ([NoEvent,SomeEvent] !!) 

pollEvent :: IO Event 
pollEvent = randomIO 

और एक Combinator, उधार ली गई और an earlier answer से अनुकूलित का उपयोग करना, कि पहली बार विधेय में विफल रहता है

spanM :: (Monad m) => (a -> Bool) -> m a -> m [a] 
spanM p a = do 
    x <- a 
    if p x then do xs <- spanM p a 
       return (x:xs) 
     else return [x] 

का मूल्यांकन बंद हो जाता है की अनुमति देता है, के लिए उदाहरण:

*Main> spanM (/= NoEvent) pollEvent 
[SomeEvent,SomeEvent,NoEvent]
+0

बहुत नौसिखिया दोस्ताना संस्करण, आपको भी धन्यवाद :) – user341228

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