将IO输出收集到列表中

时间:2010-05-16 14:43:12

标签: haskell io monads

如果输出为SDL.NoEvent并将所有结果收集到列表中,如何向SDL.pollEvent :: IO Event发出多个调用?

用命令式的术语:

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

5 个答案:

答案 0 :(得分:4)

您可以使用以下内容:

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

答案 1 :(得分:4)

James Cook非常友好地使用此功能扩展monad-loop

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

与SDL一起使用:

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

答案 2 :(得分: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上的“List”包中的

ListT

答案 3 :(得分:1)

将这些存根用于EventpollEvent

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]

答案 4 :(得分:0)

我最终在hackage的实际SDL游戏中偶然发现了这个代码片段

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)

感谢您的回答btw!