Haskell/Solutions/Understanding monads
These solutions are for an old version of Haskell/Understanding monads. Some of these exercises were left out of the book, others were incorporated to other chapters. |
Random Number Generation
[edit | edit source]Exercises |
---|
|
2. Using randomNext
, Seed
and rollDie
as defined in the chapter:
rollNDice :: Int -> Seed -> ([Int], Seed) rollNDice 0 seed = ([], seed) rollNDice n seed = let (die, seed0) = rollDie seed (rest, seed1) = rollNDice (n-1) seed0 in ((die : rest) , seed1)
The function gains the first die and seed and then recursively calls itself to roll N number of die which, once RollNDice
reaches the base case, in turn builds up a list of die. The function then returns the list of die and the final seed that was passed to the base case, rollNDice 0 seed = ([], seed)
.
3. We use mkStdGen to get the computer's random number generator and we give it an arbitrary number, 232. Firstly with import System.Random
at the top of your file:
type Seed = StdGen
rollDie1 :: Seed -> (Int, Seed) rollDie1 seed = randomR (1,6) seed
In Prelude:
Main> rollDie1 (mkStdGen 232) (3,1017593109 40692)
Threading the State with bind
[edit | edit source]Exercises |
---|
|
1. You have seen everything below the definition of (>>==)
before. So everything up to that point is just there to set everything up. I've named >>= >>==
and return return1
because this chapter uses bind and return to deal with random numbers specifically; whereas the real bind and return are more generalised and thus do not work for reasons that are somewhere over -----------------> there. At least it works; what more do you want from me? Blood?
With import System.Random
at the top of your file:
type Seed = StdGen type Random1 a = Seed -> (a, Seed) rollDie :: Random1 Int rollDie seed = randomR (1,6) seed (>>==) :: Random1 a -> (a -> Random1 b) -> Random1 b (>>==) m g = \seed0 -> let (result1, seed1) = m seed0 (result2, seed2) = (g result1) seed1 in (result2, seed2) return1 :: a -> Random1 a return1 x = \seed0 -> (x, seed0) rollNDice1 :: Int -> Random1 [Int] rollNDice1 0 = return1 [] rollNDice1 n = rollDie >>== (\d1 -> rollNDice1 (n-1) >>== (\rest -> return1 (d1 : rest)))
In prelude:
*Main> rollNDice1 20 (mkStdGen 231) ([4,3,1,1,2,3,5,4,2,5,6,4,6,2,4,5,6,5,1,5],1927676552 238604751)
In case you're wondering: You pass (mkStdGen 232111)
to rollNDice1 because rollNDice 20
on its own only creates a Random1 [Int]
; you need to pass the newly formed Random1 [Int]
a seed, in the form of (mkStdGen 242)
, to get it shooting out random numbers.
Input/Output needs bind
[edit | edit source]Exercises |
---|
|
1.
putString :: String -> IO () putString [] = putChar '\n' putString (s:xs) = putChar s >> putString xs
The State Monad
[edit | edit source]Exercises |
---|
Correct the definition for (>>=) to take the State constructor into consideration. You'll need to use pattern matching to remove the State constructor. |
(State a) >>= f = State $ \s -> let (a',s') = a s (State b) = f a' in b s'
Exercises |
---|
|
a >>= f = State $ \s -> let (a',s') = runState a s in runState (f a') s'