Сбор выводов IO в список

Как я могу издать множественные приказы к SDL.pollEvent :: IO Event пока вывод не SDL.NoEvent и соберите все результаты в список?

В обязательных терминах что-то вроде этого:

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

7
задан Flow 8 July 2012 в 18:06
поделиться

5 ответов

Джеймс Кук любезно расширил monad-loop с этим функция:

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

используется с SDL:

events <- unfoldWhileM (/= SDL.NoEvent) SDL.pollEvent
4
ответ дан 6 December 2019 в 23:02
поделиться

Вы можете использовать что-то вроде:

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

4
ответ дан 6 December 2019 в 23:02
поделиться

Использование этих заглушек для 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]
1
ответ дан 6 December 2019 в 23:02
поделиться

в итоге я наткнулся на этот фрагмент кода в реальной 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)

спасибо за ваши ответы!

0
ответ дан 6 December 2019 в 23:02
поделиться

Вы можете использовать монадические списки:

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.

2
ответ дан 6 December 2019 в 23:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: