I made this function:
-- Generates multiple random values
randoms :: (Random a) => StdGen -> Int -> a -> a -> ([a], StdGen)
randoms rndGen nbrsCount min max = randomNbrs' nbrsCount min max ([], rndGen) where
randomNbrs' rndGen 0 min max cumul = cumul
randomNbrs' rndGen count min max cumul = randomNbrs' rndGen (count-1) min max (values, snd rndGen') where
rndGen' = randomR (min, max) rndGen
values = fst rndGen' : values
and its hard to read. I can't find how to improve its readability though since I'm new to Haskell. How can this be made easier to read and more concise?
Well there are a few simple things you can do off the bat. First, you can use pattern matching to decompose your tuples without multiple expressions. You also don't need to pass around an instance of your random generator, since you already have it in your tuple, again pattern matching will let you access it.
randoml :: (Random a, RandomGen b)=> b -> Int -> a -> a -> ([a], b)
randoml rndGen nbrsCount minVal maxVal = randomNbrs' nbrsCount ([], rndGen)
where
randomNbrs' 0 cumul = cumul
randomNbrs' count (values, gen) = randomNbrs' (count-1) (newVal:values, newGen)
where
(newVal, newGen) = randomR (minVal, maxVal) gen
I renamed some of your variables as they conflict with other names in either Prelude
or System.Random
.
Now this is already looking a lot cleaner. The next step you could go for would be adding a foldr
instead of your explicit recursion. It is sort of idiomatic Haskell. If you haven't used a fold yet, don't worry you will get to it soon. A fold is really just a way to express a common form of recursion where you operate over a collection of items, accumulating the final result as you go.
randoml :: (Random a, RandomGen b)=> b -> Int -> a -> a -> ([a], b)
randoml rndGen nbrsCount minVal maxVal = foldr (\ _ (vals, gen) ->
let
(val, newGen) = randomR (minVal, maxVal) gen
in
(val:vals, newGen))
([], rndGen) [0..nbrsCount-1]
Or if you prefer without the lambda expression
randoml :: (Random a, RandomGen b)=> b -> Int -> a -> a -> ([a], b)
randoml rndGen nbrsCount minVal maxVal = foldr func ([], rndGen) [0..nbrsCount-1]
where
func _ (vals, gen) = (val:vals, newGen)
where
(val, newGen) = randomR (minVal, maxVal) gen