我已经定义了一个函数,用于从下限和上限之间的无限随机数列表中获取1个素数:
randomNumbers :: Random a => a -> a -> [a]
randomNumbers bottom top = randomRs (bottom, top) $ unsafePerformIO newStdGen
-- | Generates a random prime number of k bits length
randPrime :: Integer -> Integer
randPrime k = head $ filter isPrime ( randomNumbers (2^(k-1)) ((2^k)-1) )
但有时我需要两个唯一的素数p
和q
p =! q
。
这感觉完全错了:
-- | Generates random prime number q until it differs from a given prime number p
randUniquePrime :: Integer -> Integer -> Integer
randUniquePrime p k
| q == p = randUniquePrime p k
| otherwise = q
where q = genPrime k
最有效的方法是什么?功能和方法是什么?
答案 0 :(得分:2)
首先,您永远不想使用unsafePerformIO
。是的,它有效用途,但作为初学者,你永远不想触摸它。因此,我们先修复randomNumbers
和randPrime
。
randomNumbers :: Random a => a -> a -> IO [a]
randomNumbers bottom top = randomRs (bottom, top) <$> newStdGen
-- | Generates a random prime number of k bits length
randPrime :: Integer -> IO Integer
randPrime k = head . filter isPrime <$> randomNumbers (2^(k-1)) ((2^k)-1)
现在要获得多个素数,我们可以让randPrime
返回素数列表并从该列表中过滤重复项:
import Data.List (nub)
-- | Generates random prime numbers of k bits length
randPrimes :: Integer -> IO [Integer]
randPrimes k = filter isPrime <$> randomNumbers (2^(k-1)) ((2^k)-1)
-- | Generates random prime numbers of k bits length
randUniqPrimes :: Integer -> IO [Integer]
randUniqPrimes k = nub <$> randPrimes k
-- Now we can get any number including two unique random primes using take
-- or similar.
randPrimePair :: Integer -> IO (Integer, Integer)
randPrimePair k = (\(x:y:_) -> (x,y)) <$> randUniqPrimes k
如果您在不使用IO
的情况下不知道如何正常使用unsafeCoerce
,这是一个非常简短的介绍:
如果您的值为IO a
类型且函数为a -> b
,则可以使用
fmap, (<$>) :: (a -> b) -> (IO a -> IO b)
-- eg.
nub <$> randPrimes k
-- or
fmap nub (randPrimes k)
应用该功能。
应用一个多个IO
值的多个参数的函数。为此,有
(<*>) :: IO (a -> b) -> (IO a -> IO b)
-- which you can use like this:
getThreeLines :: IO (String, String, String)
getThreeLines = (,,,) <$> getLine <*> getLine <*> getLine
-- Reminder:
(,,,) :: a -> b -> c -> (a, b, c)
如果您的值为IO a
类型且值为a -> IO b
,则可以使用
(=<<) :: (a -> IO b) -> (IO a -> IO b)
-- or the commonly used ugly flipped variant
(>>=) :: IO a -> (a -> IO b) -> IO b
-- eg.
print =<< getLine
有时您可能需要将纯值提升到IO
,因为pure :: a -> IO a
。 pure
通常也名为return
。