Haskell: working with monads
As an assignment, I need to work with monads in Haskell and create a gambling game that has one simple rule: roll 6 coins, count heads, roll a dice and if its result is equal to or greater than the number of heads counted, you will win. otherwise you will lose. I was given the following "structure" defining the gambling Monad:
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 :: MonadGamble m => m Outcome
game = undefined
However I am still new to Monads and I have no idea how to work with them. For example: the game definition should implement the game described above, but how do I work with this Monarchy of Gambling to, for example, execute one or more rolls / rolls and get the resulting values, can I use / work with them?
Also from my understanding Monad always has two default functions: return and (-> =), but I don't see how this applies to MonadGable monad?
If anyone can help me it is greatly appreciated!
Regards, Skyfe.
First, MonadGamble
here is technically not a monad, but a style class that extends the monad so that it has two things related to it: toss
and roll
, each of which denotes a value to cast or toss respectively, In a type signature game
, m
is a monad, and it is an instance MonadGamble
so we automatically access us toss
and roll
.
You can use Haskell notation here. I won't go into details because I don't want to do the whole job, but here's how you could write a monad that checks if two coins are the same:
twoFlips :: MonadGamble m => m Bool
twoFlips = do
coin1 <- toss
coin2 <- toss
return (coin1 == coin2)
You can also find a useful function replicateM
from Control.Monad
that allows us to repeat the monadic action and return the results to a list:
import Control.Monad (replicateM)
tenCoins :: MonadGamble m => m [Coin]
tenCoins = replicateM 10 toss
You can think of it MonadGamble
as a mini-language with four constructs:
do
x <- a
b
which runs the program a
, followed by the program b
(where in the b
variable x
refers to the result a
),
return x
it is a simple program that simply returns x
,
toss
is a simple program that flips a coin once and returns the result (heads or tails), and
roll
it is a simple program that rolls the die once and returns the result (one of six faces D1
- D6
).
Note that Monad
do
and return
are also language constructs MonadGamble
; this is what the Monad m =>
declaration means MonadGamble
.
What you need to do is write a program that implements the described game using the four "constructs" defined above. Since you are new to monads, you probably want to write a game using only these four constructs, consider how you can simplify it by writing your own helper functions, and then look at the standard monad library to see what the names it gives for your helper functions (I doubt you need something that it doesn't have).
For starters, here's a program that rolls a die and then flips a coin once or twice, depending on the outcome:
-- | Roll the die, then if the result is 1-3 flip the coin once, otherwise twice,
-- returning a list of the results.
roller = do
d <- roll
if d 'elem' [ D1, D2, D3 ]
then do
c <- flip
return [ c ]
else do
c0 <- flip
c1 <- flip
return [ c0, c1 ]