Вопрос
Как я могу выдать несколько звонков на SDL.pollEvent :: IO Event
пока вывод не будет SDL.NoEvent
и соберите все результаты в список?
В императивных условиях что-то вроде этого:
events = []
event = SDL.pollEvent
while ( event != SDL.NoEvent ) {
events.add( event )
event = SDL.pollEvent
}
Решение
Джеймс Кук был так добр, чтобы продлить монад-петляс этой функцией:
unfoldWhileM :: Monad m => (a -> Bool) -> m a -> m [a]
Используется с SDL:
events <- unfoldWhileM (/= SDL.NoEvent) SDL.pollEvent
Другие советы
Вы могли бы использовать что-то вроде:
Takewhemilem :: (a -> bool) -> IO A -> IO [A] ACT WHITHECHILEM P = DO X <- ACT Если PX Тогда сделайте XS <- RecainWickilem P ATT RETURN (X: XS) еще возврата [
Вместо:
DO XS <- RecakhemeM P ATT RETTAL (X: XS)
Вы также можете использовать:
liftM (x:) (takeWhileM p act)
Урожайность:
Takewhemilem :: (a -> bool) -> IO A -> IO [A] ACT WHITHILEM P = DO X <- ACT, если PX, затем SiteM (X :) (ACTHICHILEM P AT))
Тогда вы можете использовать: takeWhileM (/=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
Из пакета «Список» на Gackage.
Используя эти заглушки для 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, например:
* Главная> Spanm (/ = NoEvent) Pollevent [Someevent, Someevent, NoEvent
В конечном итоге я в конечном итоге наткнулся на этот фрагмент кода в реальной SDL Game от 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)
Спасибо за ваши ответы, кстати!