修剪无限数量的随机数

问题描述 投票:1回答:2

我正在尝试修剪随机数列表,以使结果较小的列表中[0,1]中的数字总和累加到1以下的值。

从某种意义上说,这些列表前缀长度的平均值为esomehow,这很有趣。

虽然获得前缀的长度,但是我遇到了一个问题-我设法使程序在确定的无限列表或随机列表的一部分上运行,但是程序挂在无限随机列表上。我在做什么错?

import System.Random

-- Count list items that accumulate to 1.
count :: (Num a, Ord a) => [a] -> Int
count xs = 1 + length xs' 
         where xs'= takeWhile (< 1) $ scanl1 (+) xs

-- Works of infinite list 
a = (return (repeat 0.015)) :: IO [Double]
fa = fmap count a 
--67 

-- Works on trimmed list of randoms
rio = randomRIO (0::Double, 1)         
b = sequence $ take 10 (repeat rio)
fb = fmap count b 
-- fb is usually 2 to 5

-- Hangs on infinite list of randoms
c = sequence (repeat rio)
fc = fmap count c
-- fc hangs... ;(
list haskell random
2个回答
3
投票

您不能真正拥有无限数量的随机数,因为随机性太严格了。因此,您无法在对sequence的呼叫之外进行对count的呼叫。您可以尝试的一件事是在sequence本身内部对count进行部分重新实现:

count :: (Num a, Ord a, Monad m) => [m a] -> m (Maybe Int)
count = go 0 0
  where go n total [] = pure Nothing
        go n total (x:xs) = do
          num <- x
          let total' = total + num
              n' = succ n
          if total' >= 1
            then pure $ Just n'
            else go n' total' xs

我还修改了结果以返回Maybe,因为为空列表返回1(就像您的列表一样),或者返回列表的长度(即使其元素的总和小于1也是错误的。) >

另一个合理的变化是不接受[m a],而只接受一个m a,它可以可靠地多次产生一个值。然后,我们不必担心输入即将用完,因此不需要Maybe:

count :: (Num a, Ord a, Monad m) => m a -> m Int
count m = go 0 0
  where go n total = do
          num <- m
          let total' = total + num
              n' = succ n
          if total' >= 1
            then pure n'
            else go n' total'

然后您可以简单地调用count $ randomRIO (0::Double, 1),它将产生所需数量的随机数。


2
投票

您可以定义一个IO操作来创建无限范围的随机数流,如下所示:

© www.soinside.com 2019 - 2024. All rights reserved.