Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell: Chaining State Monad

Tags:

haskell

If I have a function that shuffles a "deck of cards", how do I use the State Monad to iterate through a defined set number of shuffles and then return a result?

For example I have the following function that will do 1 shuffle of the deck then return a specific card:

step :: State [String] String
step = do
  modify shuffle
  deck <- get
  pure $ bestCard deck

What I would like to be able to do is iterate through the state changes 5 times before I return the value.

What I have tried is this:

steps :: Int -> State [String] String
steps n = case n of
  0 -> do
    deck <- get
    pure $ bestCard deck
  _ -> do
    modify shuffle
    steps (n - 1)

but that looks far from being the correct way of doing it, even though it works.

NB. I am aware this can be done without using State Monad but I am trying to use this example to learn how to use State.

edit:

Thanks to @Koterpillar, I can use replicateM to get what I want.

evalState (replicateM n $ modify shuffle >> get >>= pure . bestCard)

like image 422
matt Avatar asked Jan 26 '23 09:01

matt


1 Answers

The most succinct way to do it is replicateM_, which repeats a monadic action a specified number of times and discards the result:

replicateM_ 5 $ modify shuffle

Because State is a monad, you only have to care about repeating an action, not specifically working with State. I found the above function by searching Hoogle for the signature of the function I wanted:

Monad m => Int -> m a -> m ()

Note that the result doesn't even require a monad, just an applicative:

replicateM_ :: Applicative m => Int -> m a -> m ()
like image 155
Koterpillar Avatar answered Jan 31 '23 15:01

Koterpillar