我正在尝试从Go到Haskell(通过电子邮件服务进行棋盘游戏)移植一个规模很大的项目,因为我最近很乐意编写Haskell并且很好地发现它的模型游戏逻辑。
我已经清楚地了解了我之前编写过该服务和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,这些函数的实际实现不是问题。我开始需要组合monad的那一刻就是我开始绊倒自己。
如果有人能够举例说明如何将monad组合成两个人为的功能,我将非常感激。我想,一旦我有几个例子,我可以跳过这个障碍并继续学习。
答案 0 :(得分:1)
你可以使用monad trasformer来组成一个monad,这将提供一种生成随机数,保持状态和你想要做的其他事情的方法。
让我们从MonadRandom
开始吧。文档说IO
是它的一个实例,所以我们可以将它用作基础monad:
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)))