循环使用StateT monad

时间:2017-03-17 22:31:14

标签: haskell

这是学习StateT monad的练习。该计划实施了游戏Morra。这两个玩家是计算机和一个人。州政府积累了计算机和玩家的得分。该程序适用于函数morra的一次迭代。但是我不知道如何循环它。我尝试过一些东西但似乎没什么用。

module Morra where

import Control.Monad.Trans.State.Lazy
import Control.Monad.IO.Class
import Data.Char (isDigit, digitToInt)
import System.Random (randomRIO)
import Control.Monad (when)

morra :: StateT (Int, Int) IO ()
morra = do
  p <- liftIO getChar
  when (isDigit p) $
    do
      let p' = digitToInt p
      c <- liftIO $ randomRIO (1, 2)
      liftIO $ putStrLn ['P',':',' ',p] --"P: " ++ p)
      liftIO $ putStrLn ("C: " ++ show c)
      (pt, ct) <- get
      if even (c + p') then
        do
          liftIO $ putStrLn "Computer Wins"
          put (pt, ct + 1)
      else
        do
          liftIO $ putStrLn "Player Wins"
          put (pt + 1, ct)

main :: IO ()
main = do
  putStrLn "-- p is Player"
  putStrLn "-- c is Computer"
  putStrLn "-- Player is odds, Computer is evens."
  fScore <- runStateT morra (0,0)
  let personS = fst . snd $ fScore
      compS = snd . snd $ fScore
  putStrLn ("Person Score: " ++ show personS)
  putStrLn ("Computer Score: " ++ show compS)
  if personS > compS then
    putStrLn "Winner is Person"
  else
    putStrLn "Winner is Computer"

2 个答案:

答案 0 :(得分:2)

你在那里99%。只需在最后一个main之后的新行添加putStrLnmain将自行调用,有效地重新启动该程序。

简化代码中的一些操作的一些技巧:

  • 使用execStateT :: StateT s m a -> s -> m s获取该回合的最终状态。这样,您就不需要使用let绑定来提取分数,而是可以内联代替:(personS,compS) <- execStateT morra (0,0)
  • ['P',':',' ',p]可以写成("P: " ++ [p])

这是风格和偏好的问题,但您可以通过重新排列ifelsedo来减少大量缩进和格式化空白:

if condition
  then do
    doSomethingA
    doSomethingB
  else someFunction $ do
    doSomethingElseA
    doSomethingElseB

总的来说,干得好:)

答案 1 :(得分:1)

我用p <- liftIO getChar替换p <- liftIO getLine并进行了一些其他的小改动,以允许p现在是String而不是Char。现在它有效。似乎它与Windows有关,因为它在linux上使用getChar。这是最终的代码:

module Morra where

import Control.Monad.Trans.State.Lazy
import Control.Monad.IO.Class
import Data.Char (isDigit, digitToInt)
import System.Random (randomRIO)
import Control.Monad (when)

morra :: StateT (Int, Int) IO ()
morra = do
  p <- liftIO getLine
  let p1 = head p
  when (isDigit p1) $ do
    let p' = digitToInt p1
    c <- liftIO $ randomRIO (1, 2)
    liftIO $ putStrLn ("P: " ++ p)
    liftIO $ putStrLn ("C: " ++ show c)
    (pt, ct) <- get
    if even (c + p') then do
      liftIO $ putStrLn "Computer Wins"
      put (pt, ct + 1)
    else do
      liftIO $ putStrLn "Player Wins"
      put (pt + 1, ct)
    morra

main :: IO ()
main = do
  putStrLn "-- p is Player"
  putStrLn "-- c is Computer"
  putStrLn "-- Player is odds, Computer is evens."
  (personS,compS) <- execStateT morra (0,0)
  putStrLn ("Person Score: " ++ show personS)
  putStrLn ("Computer Score: " ++ show compS)
  if personS == compS then
    putStrLn "No Winner"
  else if personS > compS then
    putStrLn "Winner is Person"
  else
    putStrLn "Winner is Computer"