硬币和骰子与单子

时间:2014-10-15 09:42:17

标签: haskell monads

我试图做一个简单的游戏"使用monads
我扔了六次硬币并计算了数字 我看到的头,然后我掷骰子;
 如果骰子上的眼睛数量更多 超过或等于我计算的头数然后我赢了,否则我输了

我声明了以下类型

data Coin = H | T
deriving (Bounded, Eq, Enum, Ord, Show)

data Dice = D1 | D2 | D3 | D4 | D5 | D6
deriving (Bounded, Eq, Enum, Ord, Show)

data Outcome = Win | Lose
deriving (Eq, Ord, Show)

然后我继续定义

class Monad m => MonadGamble m where
toss :: m Coin
roll :: m Dice

在我的脑海中,当调用折腾或滚动时,应提供骰子或硬币值,但它不会

然后我尝试按如下方式编写游戏代码

game = do
        i <- 0
        x <- [toss, toss, toss, toss, toss, toss]
        if x==H
            then do 
                    i <- i+1
                    []
            else []
        y <- roll
        if y > i
            then Win
            else Lose

然而它不起作用,因为我在do块中做了一些完全错误的事情,可能是因为我对monads缺乏了解 有人可以在这里提供一些建议吗?

1 个答案:

答案 0 :(得分:6)

首先,在Haskell中,您无法分配i = i + 1之类的变量。在Haskell中,变量始终绑定到单个值。 do notation中使用的符号<-始终将变量绑定到monadic操作的结果,并且整个do块中的monad必须相同。并且do块中的每个语句都必须是monadic动作,除非它是let绑定。特别是:

 -- isn't allowed because 0 is a number, not something of type 'm X':
 i <- 0
 -- isn't allowed because a list is not a monadic action:
 x <- [toss, toss, toss, toss, toss, toss]
 ...
                i <- i+1  -- can't re-assign a variable
                []        -- must be a monadic action, so this must be 'result []'
 ...
    if y > i
        then Win   -- again must be 'return Win'
 ...

此外,在if y > i中,您要将iy类型Dice进行比较,这是不允许的。相反,我建议您放弃Dice并让toss返回一个数字。修正后的版本可能如下所示:

import Control.Monad

data Coin = H | T
  deriving (Bounded, Eq, Enum, Ord, Show)

data Outcome = Win | Lose
  deriving (Eq, Ord, Show)

class Monad m => MonadGamble m where
    toss :: m Coin
    roll :: Int -> m Int

game :: (MonadGamble m) => m Outcome
game = do
    x <- replicateM 6 toss -- is of type m [Coin]
    let i = length (filter (== H) x)
    y <- roll 6
    if y > i
        then return Win
        else return Lose

请注意,要运行game,您需要编写MonadGamble的实现。