2017-03-17 51 views
0

這是學習StateT monad的練習。該程序實現了遊戲莫拉。這兩名球員是電腦和一個人。國家累計電腦和玩家的分數。該程序適用於morra函數的一個迭代。然而,我不知道如何循環它。我嘗試了一些東西,但似乎沒有任何工作。與StateT monad環路

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

你99%了。只需在最後一個putStrLn之後的新行上添加mainmain即可自行調用,有效地重新啓動程序。

一些技巧來簡化一些東西在你的代碼:

  • 使用execStateT:: StateT s m a -> s -> m s僅舉輪的最終狀態。這樣,您就不需要使用let綁定提取得分,並且可以做到這一點內嵌代替:(personS,compS) <- execStateT morra (0,0)
  • ['P',':',' ',p]可以寫爲("P: " ++ [p])

它的風格和偏好的問題,但

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

總的來說,不錯:)

01:您可以通過重新安排 if S, else S和 do■減少了很多的縮進和格式化空白
+0

感謝您的。不過,我需要Morra函數的循環。函數main只能運行一次。如果我將'morra'放在函數的末尾(與'when'後面的'do'一致),則什麼都不會發生。 – user1897830

+0

@ user1897830你需要把它和'when'(只縮進兩個空格)放在一起。如果你把它放在when中,它只會在'isDigit p'爲true時循環。 「什麼都沒有發生」是什麼意思?它會立即退出,還是會陷入循環? – Lazersmoke

+0

我需要它僅在'isDigit p'爲true時循環。這是循環直到'isDigit p'不正確,然後退出。但是,當我把morra放在它剛剛退出並且不循環的時候。 – user1897830

1

我換成p <- liftIO getCharp <- liftIO getLine,並提出了其他一些小的改動,以允許事實是p現在是一個字符串,而不是一個字符。現在它可以工作。似乎它與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"