硬币和骰子与单子

Lor*_*les 0 monads haskell

我正在尝试使用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)
Run Code Online (Sandbox Code Playgroud)

然后我继续定义

class Monad m => MonadGamble m where
toss :: m Coin
roll :: m Dice
Run Code Online (Sandbox Code Playgroud)

在我的脑海中,当调用折腾或滚动时,应提供骰子或硬币值,但事实并非如此

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

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
Run Code Online (Sandbox Code Playgroud)

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

Pet*_*lák 6

首先,在Haskell中你不能分配像i = i + 1.在Haskell中,变量始终绑定到单个值.符号中<-使用的do符号总是将变量绑定到monadic动作的结果,并且monad在整个do块中必须相同.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'
 ...
Run Code Online (Sandbox Code Playgroud)

此外,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
Run Code Online (Sandbox Code Playgroud)

请注意,为了运行,game您需要编写一个实现MonadGamble.

  • 序列[toss,...,toss] == replicateM 6折腾 (2认同)