这是学习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"
答案 0 :(得分:2)
你在那里99%。只需在最后一个main
之后的新行添加putStrLn
,main
将自行调用,有效地重新启动该程序。
简化代码中的一些操作的一些技巧:
execStateT
:: StateT s m a -> s -> m s
获取该回合的最终状态。这样,您就不需要使用let
绑定来提取分数,而是可以内联代替:(personS,compS) <- execStateT morra (0,0)
['P',':',' ',p]
可以写成("P: " ++ [p])
这是风格和偏好的问题,但您可以通过重新排列if
,else
和do
来减少大量缩进和格式化空白:
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"