首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >迭代IO操作和懒惰

迭代IO操作和懒惰
EN

Stack Overflow用户
提问于 2016-01-20 21:32:17
回答 1查看 135关注 0票数 0

我想写Hangman游戏https://github.com/fokot/reactive-hangman/blob/master/src/Hangman.hs,并将用户操作列表视为懒惰流。我的递归版本工作正常(在代码runGameRecursively (newGameState“保密”)中)

我在懒惰问题上陷入困境

代码语言:javascript
复制
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")

当你运行游戏时,每个步骤都需要重新评估所有先前的步骤,即使它们已经是了。我试着玩$!但还没有找到正确的答案。谢谢

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-01-23 23:14:28

我认为使用iterate编制一个表面上纯粹的IO操作列表的方案是这里麻烦的根源。您的计划是按用户输入更新状态,但将状态继承视为可以“像列表一样对待”的流。如果我使用一个真正的iterateM来生成一个合适的流东西,那么事情就会和你想要的完全一样。所以如果我把进口

代码语言:javascript
复制
import Streaming -- cabal install streaming
import qualified Streaming.Prelude as S

在您的主要定义之后,编写如下

代码语言:javascript
复制
runGameInfiniteStream gs =  S.print $ S.take 1 $ S.dropWhile (not . gameEnded) steps
  where
  steps :: Stream (Of GameState) IO ()
  steps = S.iterateM updateGameState (return gs)

main :: IO ()
main = runGameInfiniteStream (newGameState "car")

然后我得到

代码语言:javascript
复制
>>> main
You have 5 lifes. The word is "___"
Guess a letter: 
c
You have 5 lifes. The word is "c__"
Guess a letter: 
a
You have 5 lifes. The word is "ca_"
Guess a letter: 
r
GameState {secretWord = "car", lives = 5, guesses = "rac"}

我认为这正是您想要的程序,但是使用适当的流概念,而不是以某种复杂的方式混合IO和列表。pipesconduit以及类似的软件包也可以实现类似的功能。

(后加:)

要流到与一个纯粹的Chars列表相对应的状态(模拟来自用户输入的结果),只需使用scan

代码语言:javascript
复制
pureSteps
   :: (Monad m) => GameState -> [Char] -> Stream (Of GameState) m ()
pureSteps gs chars = S.scan updateState gs id (S.each chars)

这与Prelude.scanl基本相同,也可以使用它(在纯情况下)查看更新:

代码语言:javascript
复制
>>> S.print $ pureSteps (newGameState "hi") "hxi"
GameState {secretWord = "hi", lives = 5, guesses = ""}
GameState {secretWord = "hi", lives = 5, guesses = "h"}
GameState {secretWord = "hi", lives = 4, guesses = "h"}
GameState {secretWord = "hi", lives = 4, guesses = "ih"}

>>> mapM_ print $ scanl updateState (newGameState "hi") "hxi"
GameState {secretWord = "hi", lives = 5, guesses = ""}
GameState {secretWord = "hi", lives = 5, guesses = "h"}
GameState {secretWord = "hi", lives = 4, guesses = "h"}
GameState {secretWord = "hi", lives = 4, guesses = "ih"}

要查看最终的“获胜”状态,如果存在,可以编写。

代码语言:javascript
复制
runPureInfinite
  :: Monad m => GameState -> [Char] -> m (Of [GameState] ())
runPureInfinite gs = S.toList . S.take 1 . S.dropWhile (not . gameEnded) . pureSteps gs

-- >>> S.print $ runPureInfinite (newGameState "car") "caxyzr"
-- [GameState {secretWord = "car", lives = 2, guesses = "rac"}] :> ()

诸若此类。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34910992

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档