Как я могу издать множественные приказы к SDL.pollEvent :: IO Event
пока вывод не SDL.NoEvent
и соберите все результаты в список?
В обязательных терминах что-то вроде этого:
events = []
event = SDL.pollEvent
while ( event != SDL.NoEvent ) {
events.add( event )
event = SDL.pollEvent
}
Джеймс Кук любезно расширил monad-loop с этим функция:
unfoldWhileM :: Monad m => (a -> Bool) -> m a -> m [a]
используется с SDL:
events <- unfoldWhileM (/= SDL.NoEvent) SDL.pollEvent
Вы можете использовать что-то вроде:
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
Использование этих заглушек для 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
и комбинатора, заимствованного и адаптированного из предыдущего ответа, который прекращает вычисление при первом сбое предиката
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]
в итоге я наткнулся на этот фрагмент кода в реальной 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)
спасибо за ваши ответы!
Вы можете использовать монадические списки:
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
из пакета "List" на hackage.