我想生成一个包含26个随机整数的列表,其中Haskell的总和为301。我写了以下内容:
import System.Random
f 1 sum = [sum]
f n sum = m : (f (n-1) (sum-m))
where m = randomRIO (0,sum)
但它无法编译!我对IO感到困惑!
Occurs check: cannot construct the infinite type: a1 = IO a1
In the first argument of `(:)', namely `m'
In the expression: m : (f (n - 1) (sum - m))
In an equation for `f':
f n sum
= m : (f (n - 1) (sum - m))
where
m = randomRIO (0, sum)
答案 0 :(得分:8)
在这种情况下,错误消息有点令人困惑,但最重要的是你需要在IO
monad中工作,因为它使用randomRIO
中的IO
,并且是(按设计)无法从非IO
代码运行IO
代码。
f 1 sum = return [sum]
f n sum = do
x <- randomRIO (0, sum)
xs <- f (n - 1) (sum - x)
return (x : xs)
答案 1 :(得分:5)
除了锤子所写的内容之外,如果你编写了f
函数所期望的类型,错误信息会变得更加清晰:
f :: Int -> Int -> [Int]
f 1 sum = [sum]
f n sum = m : (f (n-1) (sum-m))
where m = randomRIO (0,sum)
给出错误:
Couldn't match expected type `Int' with actual type `IO Int'
In the first argument of `(:)', namely `m'
In the expression: m : (f (n - 1) (sum - m))
In an equation for `f':
f n sum
= m : (f (n - 1) (sum - m))
where
m = randomRIO (0, sum)
Failed, modules loaded: none.
这几乎可以告诉你到底出了什么问题 - m
类型IO Int
而不是Int
答案 2 :(得分:5)
正如其他人所指出的那样,你的算法不会给出均匀分布的输出。
获得统一输出的简便方法是:
n-1
到0
(含)范围内的sum
个随机数0
和sum
插入随机数列表示例:
[72,33,43]
0
和100
并对列表进行排序,并提供[0,33,43,72,100]
[33-0, 43-33, 72-43, 100-72]
[33,10,29,28]
在Haskell:
randomsWithSum :: (Num n, Ord n, Random n) => Int -> n -> IO [n]
randomsWithSum len sum =
do b <- sequence $ take (len-1) $ repeat $ randomRIO (0,sum)
let sb = sort (sum:b) in
return $ zipWith (-) sb (0:sb)
对于您的示例,您可以将其称为randomsWithSum 26 (301::Int)
这同样适用于浮点类型,例如: randomsWithSum 4 (1::Double)
编辑交换参数,以便26 `randomsWithSum` 301
执行其名称所暗示的内容。
答案 3 :(得分:0)
根据demas的评论,我试图调整你的算法。我们可能希望每个n
数字与其他数字“相同”,所以我们只会尝试直到得到正确的总和。也许有更好的方法。
-- f 0 rng = return []
-- f n rng = randomRIO (0,rng) >>= (\x-> fmap (x:) $ f (n-1) rng)
g n sumval =
let s = 2*sumval `div` n -- expected value upto z is probably z/2,
h i = do -- if all are equally likely
xs <- sequence $ replicate n (randomRIO (0,s))
if sum xs == sumval
then return (xs, i) -- i is number of attempts
else h (i+1)
in h 1
-- test:
Prelude System.Random> g 26 301
([15,23,15,0,13,8,23,11,13,19,5,2,10,19,4,8,3,9,19,16,8,16,18,4,20,0],2)
Prelude System.Random> g 26 301
([20,14,3,6,15,21,7,9,2,23,22,13,2,0,22,9,4,1,15,10,20,7,18,1,18,19],12)
Prelude System.Random> g 26 301
([4,3,4,14,10,16,20,11,19,15,23,18,10,18,12,7,3,8,4,9,11,5,17,4,20,16],44)
Prelude System.Random> g 26 301
([6,6,22,1,5,14,15,21,12,2,4,20,4,9,9,9,23,10,17,19,22,0,10,14,6,21],34)
Prelude System.Random> g 26 301
([20,9,3,1,17,22,10,14,16,16,18,13,15,7,6,3,2,23,13,13,17,18,2,2,8,13],169)