【发布时间】:2016-04-26 22:41:07
【问题描述】:
我想编写 Hangman 游戏 https://github.com/fokot/reactive-hangman/blob/master/src/Hangman.hs,并将用户操作列表视为惰性流。我的递归版本工作正常(在代码中 runGameRecursively (newGameState "secret"))
我陷入了懒惰的问题
updateGameState :: GameState -> IO GameState
updateGameState gs = do
l <- getALetter gs
return $ updateState gs l
ff :: (a -> Bool) -> [IO a] -> IO a
ff f (i:is) = do
res <- i
if f res then return res else ff f is
runGameInfinite :: GameState -> IO ()
runGameInfinite gs =
-- infinite lazy game loop
let repl = tail $ iterate (\x -> x >>= updateGameState) (return gs) :: [IO GameState]
in do
endState <- ff gameEnded repl
putStrLn $ showState endState
main = runGameInfinite (newGameState "car")
当您运行游戏时,repl 中的每一步都需要重新评估所有之前的步骤,即使它们已经存在。我试着玩 $!但还没有找到正确的答案。谢谢
【问题讨论】:
-
“我做不到”不是问题 - 您已经包含了一行代码,但甚至没有包含运行此假设代码时收到的错误消息。如果您尝试过它并给出了错误,为什么不包括错误以节省人们一些时间呢?您应该将您的问题隔离到足够小的代码以放入您的问题
-
好的,我玩了它并进一步编辑了问题。
-
现在问题很明显 - IO 并不懒惰。像你一样使用 IO 肯定是一种反模式。如果您希望它与 IO 一起使用,则必须使用
unsafeInterleaveIO,这显然很糟糕。最好从 IO 中删除游戏的逻辑,然后所需的语义(即takeWhile p someInfiniteList和变体)将按预期工作。而不是updateGameState :: GameState -> IO GameState,您必须拥有updateGameState :: UserInput -> GameState -> GameState,然后readUserInput :: IO [UserInput]是微不足道的——只需map read . lines <$> getContents。
标签: haskell reactive-programming frp