我需要为测试目的生成一些随机数.我之前从未使用过Data.Random.我需要做很多测试,我不知道提前需要的数量,但我知道它们应该落入某个界限.我写了这个函数:
import System.Random
f k = (\(x,y) -> x*y < (10^k) && x*y >0 )
rands n g k = take n $ filter (\(x,y) -> x*y < (10^k) && x*y >0 ) (zip a b)
where a = randomRs (1::Int, 10^k-1) ga
b = randomRs (1::Int, 10^k-1) gb
(ga, gb) = split $ mkStdGen g
Run Code Online (Sandbox Code Playgroud)
并开始使用它生成的数字来测试事物.使用此功能时我开始注意到奇怪的事情:
testRands n k = do
g1 <- randomIO
g2 <- randomIO
let r = rands n (mkStdGen g1, mkStdGen g2) k
putStrLn $ show r
putStrLn $ show $ map (\(x,y) -> x*y < 10^k && x*y >0) r
putStrLn $ show $ map (\(x,y) -> x*y) r
putStrLn $ show $ maximum $ map (\(x,y) -> x*y) r
*Main> testRands 4 7
[(6193574,9385226),(9634973,5475375),(5070277,7408626),(3801396,5652588)]
[True,True,True,True]
[4353660,6993107,2038586,4030960]
6993107
Run Code Online (Sandbox Code Playgroud)
然后我复制它生成的数字并将它们粘贴回GHCI并在所有这些上调用完全相同的谓词函数:
*Main> map (f 7) [(6193574,9385226),(9634973,5475375),(5070277,7408626),(3801396,5652588)]
[False,False,False,False]
Run Code Online (Sandbox Code Playgroud)
这没有任何意义,我甚至不知道从哪里开始尝试修复它.
在您的程序中,您将Int在以下行中显式生成类型的值:
where a = randomRs (1::Int, 10^k-1) ga
b = randomRs (1::Int, 10^k-1) gb
Run Code Online (Sandbox Code Playgroud)
如果您使用的是32位计算机,则生成的数字的乘法可能会导致溢出.例如:
> 6193574 * 9385226 :: Int
4353660
Run Code Online (Sandbox Code Playgroud)
但是,文字本身是超载的.因此,如果将它们粘贴到GHCi中,那么它们将被默认为(无界)Integer类型,它们不会溢出:
> 6193574 * 9385226 :: Integer
58128091737724
Run Code Online (Sandbox Code Playgroud)
这解释了应用谓词的困难结果.
因此要么生成Integer而不是Int,要么添加一个类型注释,说明您传递的列表[Int]而不是[Integer]使结果匹配.