如果输出为SDL.NoEvent
并将所有结果收集到列表中,如何向SDL.pollEvent :: IO Event
发出多个调用?
用命令式的术语:
events = []
event = SDL.pollEvent
while ( event != SDL.NoEvent ) {
events.add( event )
event = SDL.pollEvent
}
答案 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)
将这些存根用于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]
答案 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!