我做了这个功能:
-- 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
并且难以阅读。因为我是Haskell的新手,所以我无法找到如何提高其可读性。如何使这更容易阅读和更简洁?
答案 0 :(得分:7)
我真的很想在这些情况下使用MonadRandom
:
import Control.Monad.Random
randomsR :: (Random a, RandomGen b) => b -> Int -> a -> a -> ([a], b)
randomsR gen nb min max = flip runRand gen -- run the random monad
. sequence -- get the random monad out of the list
. replicate nb -- generate nb values
$ getRandomR (min, max) -- the generator for one value
你也可以缩短它(感谢Ørjan):
randomsR :: (Random a, RandomGen b) => b -> Int -> a -> a -> ([a], b)
randomsR gen nb min max = flip runRand gen
. replicateM nb
$ getRandomR (min, max)
或
randomsR :: (Random a, RandomGen b) => b -> Int -> a -> a -> ([a], b)
randomsR gen nb min max = flip runRand gen
. fmap (take nb)
$ getRandomRs (min, max)
答案 1 :(得分:3)
你可以做一些简单的事情。首先,您可以使用模式匹配来分解没有多个表达式的元组。您也不需要传递随机生成器的实例,因为您已经在元组中使用它,再次使用模式匹配将允许您访问它。
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
我重命名了一些变量,因为它们与Prelude
或System.Random
中的其他名称冲突。
现在这已经看起来更清洁了。您可以采用的下一步是添加foldr
而不是显式递归。它有点像惯用的Haskell。如果您还没有使用折叠,请不要担心您会很快到达。折叠实际上只是表达一种常见递归形式的一种方式,您可以在一系列项目上操作,随时累积最终结果。
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]
或者如果您不喜欢lambda表达式
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