Problem Set 1
Random number generation
First exercise is simple. The text says not to try to do anything fancy. Well, I'm not sure what's the opposite of fancy, but it should be my forte. Here a solution:
fiveRands :: [Integer] fiveRands = [ fst $ rand $ mkSeed 1, fst $ rand $ snd $ rand $ mkSeed 1, fst $ rand $ snd $ rand $ snd $ rand $ mkSeed 1, fst $ rand $ snd $ rand $ snd $ rand $ snd $ rand $ mkSeed 1, fst $ rand $ snd $ rand $ snd $ rand $ snd $ rand $ snd $ rand $ mkSeed 1]
However, it's easy to spot a common pattern in the list of function compositions. A shorter, more general version:
fiveRands' :: [Integer] fiveRands' = map fst $ take 5 $ iterate (rand . snd) $ rand $ mkSeed 1
I was initially surprised to see it working, since the first element
on the array in the first defition is fst $ rand $ mkSeed 1
, that
is, there's no occurrence of the composite function (rand
. snd)
. But it all makes sense if you observe the definition of
iterate
.
Random character generation
randLetter :: Seed -> (Char, Seed) randLetter seed = (toLetter $ fst r, snd r) where r = rand seed randString3 :: String randString3 = map fst $ take 3 $ iterate (randLetter . snd) $ randLetter $ mkSeed 1
More generators
type Gen a = Seed -> (a, Seed) myRand :: Gen Integer myRand = rand myRandLetter :: Gen Char myRandLetter = randLetter generalA :: (a -> b) -> Gen a -> Gen b generalA f g seed = (f $ fst r, snd r) where r = g seed randEven :: Gen Integer -- the output of rand * 2 randEven = generalA (\x -> x * 2) myRand randOdd :: Gen Integer -- the output of rand * 2 + 1 randOdd = generalA (\x -> x * 2 + 1) myRand randTen :: Gen Integer -- the output of rand * 10 randTen = generalA (\x -> x * 10) myRand
Generalizing random pairs
randPair :: Gen (Char, Integer) randPair seed = ((fst l, fst n), snd n) where l = randLetter seed n = rand $ snd l generalPair :: Gen a -> Gen b -> Gen (a, b) -- generalPair :: (Seed -> (a, Seed)) -> (Seed -> (b, Seed)) -> Seed -> ((a,b), Seed) generalPair gena genb seed = ((a, b), seed'') where ra = gena seed a = fst ra seed' = snd ra rb = genb seed' b = fst rb seed'' = snd rb randPair' = generalPair randLetter rand
Generalizing lists of generators
repRandom :: [Gen a] -> Gen [a] repRandom [] seed = ([], seed) -- not sure about this equation repRandom (g:gs) seed = (a : fst (repRandom gs seed'), seed') where ra = g seed a = fst ra seed' = snd ra
Threading the random number state
genTwo :: Gen a -> (a -> Gen b) -> Gen b genTwo gen f seed = f a seed where ra = gen seed a = fst ra seed' = snd ra mkGen :: a -> Gen a -- mkGen :: a -> Seed -> (a, Seed) mkGen a seed = (a, seed)