2016-02-15 56 views
1

我目前正試圖從Go to Haskell(通過電子郵件服務的棋盤遊戲)移植一個大型項目,因爲我最近很開心編寫Haskell,並且找到它模擬遊戲邏輯相當不錯。Monad變形金剛 - 隨機+錯誤+日誌爲棋盤遊戲服務

我已經清楚地知道我以前寫過服務和25場比賽要達到什麼目的,但我不確定這是實現它的最好方法,或者是如何實現它。

大部分暴露棋盤遊戲功能有以下幾點:

  • 隨機性
  • 錯誤(主要是驗證,做的事情,將打破遊戲規則時)
  • 記錄(人類可讀的日誌當事情在比賽中發生)

我一直在嘗試使用的單子有以下幾種製作:

我的問題是,我掙扎找出我怎麼能在一個單一的功能使用所有這三種。對於一個相當人爲的例子,我定義了一個類型的遊戲數據並傳遞到並從其中的一些功能返回它:

data Game = Game { rnd :: Int 
       , numPlayers :: Int 
       , deck :: [Int] 
       , hands :: [[Int]] 
       } 

-- newGame takes a player count and returns a Game. Needs randomness, errors and logging. 
newGame :: Int -> ? Game 

-- drawCard takes a player number and an existing Game and returns a Game. Needs errors and logging. 
drawCard :: Int -> Game -> ? Game 

這些各種功能的實際實現是不是一個問題,如果他們只是返回Game或使用單個monad。我開始需要結合monads的那一刻是當我開始絆倒自己的時候。

如果任何人都能提供一個例子說明如何將monads用於兩個設計好的函數,我會非常感激。我想,一旦我有幾個例子,我可以跳過這個障礙,並繼續學習,因爲我走了。

+0

您是否嘗試過寫函數,並讓它推斷出類型?或者,如果你不能這樣做,有一個相當不錯的解釋'mtl' monad變形金剛[這裏](https://en.wikibooks.org/wiki/Haskell/Monad_transformers)包括例子。 – user2407038

回答

1

您可以使用monad trasformers來組成monad,這將提供一種生成隨機數字,保持狀態和您想要執行的其他操作的方法。

讓我們從MonadRandom開始。該文件說,IO是它的一個實例,所以我們可以使用它作爲基地單子:

newtype Game a = Game (IO a) 

爲了Game存儲和修改數據讓我們成爲一個MonadState通過包裝成StateT

data GameState = GameState { 
       , numPlayers :: Int 
       , deck :: [Int] 
       , hands :: [[Int]] 
       } 

newtype Game a = Game (StateT GameState (IO a)) 

以同樣的方式,你可以教Game通過WriterT提供日誌功能:

type LogType = String 

newtype Game a = Game (WriterT LogType (StateT GameState (IO a)))