如何在SDL.pollEvent :: IO Event
之前發出多次調用,直到輸出爲SDL.NoEvent
並將所有結果收集到列表中?將IO輸出收集到列表中
在必要的條件是這樣的:
events = []
event = SDL.pollEvent
while (event != SDL.NoEvent) {
events.add(event)
event = SDL.pollEvent
}
如何在SDL.pollEvent :: IO Event
之前發出多次調用,直到輸出爲SDL.NoEvent
並將所有結果收集到列表中?將IO輸出收集到列表中
在必要的條件是這樣的:
events = []
event = SDL.pollEvent
while (event != SDL.NoEvent) {
events.add(event)
event = SDL.pollEvent
}
詹姆斯·庫克是這麼樣使用此功能擴展monad-loop S:
events <- unfoldWhileM (/= SDL.NoEvent) SDL.pollEvent
你可以用一元列表:
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
ListT
從hackage 「列表」 包。
您可以使用類似:
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 []
然後你可以使用:takeWhileM (/=SDL.NoEvent) SDL.pollEvent
我建議'takeUntilM :: Monad m =>(a - > Bool) - > ma - > m [a]'(with當'px'爲'false'時適當的'return [x]')以避免信息丟失(尤其是IO單元)。當它只是'SDL.NoEvent'時,這可能看起來很正常,但是對於「Left」系統崩潰可能是錯誤的「:: String a'。 – ony 2010-05-16 17:49:03
哦,你可能想構建懶惰列表,所以需要使用'System.Unsafe'中的'interleaveIO'(或類似的東西)。即例如'liftM(x :)(interleaveIO(unsafeTakeUntilM p act))' – ony 2010-05-16 17:56:13
'takeWhileM'的很多變體:http://stackoverflow.com/questions/1133800/haskell-monadic-takewhile/1138153#1138153 – kennytm 2010-05-16 18:47:49
我最終絆倒在實際的遊戲SDL此代碼段從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)
謝謝您的回答順便說一句!
如果這是非常受歡迎的方法,可以在不處理它的情況下一次性排出隊列中的所有事件,而不是爲什麼SDL API不直接提供它?這可能有助於避免某些同步。線程安全隊列的開銷。 – ony 2010-05-17 13:06:47
使用這些存根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
和組合子,貸款以及從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]
允許這個ghci的會議,爲例如:
*Main> spanM (/= NoEvent) pollEvent [SomeEvent,SomeEvent,NoEvent]
非常新手友好的版本,也謝謝你:) – user341228 2010-05-17 08:09:10
爲什麼 「重複()」:
與SDL使用? – Peaker 2010-05-16 15:22:08
@peaker:'repeat():: ListT IO()'是包含無關緊要的值的無限IO單子列表('()')。那麼我們用'lift pollEvent'調用'(>>)',這樣對於無限列表中的每個元素,我們都使用'pollEvent'。 'takeWhile'使其成爲一個有限單子列表,然後'toList'使其成爲':: IO [Event]'。 – yairchu 2010-05-16 15:54:03
這似乎有點怪異..也許更有意義的使用像「repeatM(lift pollEvent)」? – Peaker 2010-05-17 06:29:11