Haskell中IO Bool的列表理解
我试图通过Miller-Rabin素性检查来检查Mersenne数,从而找到可能的Mersenne素数 如果Haskell中IO Bool的列表理解,haskell,boolean,monads,Haskell,Boolean,Monads,我试图通过Miller-Rabin素性检查来检查Mersenne数,从而找到可能的Mersenne素数 如果mersennes是Mersenne数字的无限列表,我想做如下操作: probableMersennePrimes :: IO [Integer] probableMersennePrimes = [ n | n <- mersennes, primeMillerRabin n ] probableMersennePrimes::IO[整数] ProbableMersenneTim
mersennes
是Mersenne数字的无限列表,我想做如下操作:
probableMersennePrimes :: IO [Integer]
probableMersennePrimes = [ n | n <- mersennes, primeMillerRabin n ]
probableMersennePrimes::IO[整数]
ProbableMersenneTime=[n | n IO Bool
作为一个附带问题,类型应该是
IO[Integer]
还是[IO Integer]
?您可以使用管道中的ListT
来流式处理无限数量列表:
import Control.Monad
import Data.Monoid
import Pipes
mersennes :: [Integer]
mersennes = undefined
primeMillerRabin :: Integer -> IO Bool
primeMillerRabin = undefined
probableMersennePrimes :: ListT IO Integer
probableMersennePrimes = do
n <- Select (each mersennes)
continue <- lift (primeMillerRabin n)
guard continue
return n
main = runListT $ do
n <- probableMersennePrimes
lift (print n)
mempty
import-Control.Monad
导入数据.幺半群
导入管道
梅森尼斯::[整数]
梅森尼斯=未定义
primeMillerRabin::整数->IO布尔
primeMillerRabin=未定义
probableMersennePrimes::ListIO整数
probableMersennePrimes=do
n如果将primeMillerRabin
更改为RandomGen g=>Integer->State g Bool
类型,则可以使用filterM
执行此操作
probableMersennePrimes :: RandomGen g => g -> [Integer]
probableMersennePrimes = evalState $ filterM primeMillerRabin mersennes
通过使用evalState
,我们放弃了filterM primemillerabin mersennes
计算的最终状态,因此我们不能严格要求它。但这是一件好事,因为最终状态只有在我们到达mersennes
列表的末尾后才可用,它是无限的,没有尽头
这允许计算惰性地生成probableMersennePrimes gen
的元素
由于随机数生成器的工作方式,当它返回一个IO
操作时,您不能这样做。IO计算需要知道结束状态是什么,这样它才能在计算之后生成另一个随机数,因此它必须无休止地循环,寻找无尽列表的结尾
但不要只是相信我,试试看:
module SO26307073 where
import Control.Monad.State
import System.Random
-- find how many times a factor divides a number
-- (p^s * d) `factorBy` p == (s,d) iff d `rem` p /= 0
factorBy :: Integral a => a -> a -> (Int,a)
factorBy n p = (length steps - 1, fst $ last steps)
where steps = takeWhile ((==0) . snd) $ iterate (flip quotRem 2 . fst) (n, 0)
mersennes :: Num a => [a]
mersennes = [ 2^n - 1 | n <- [2..] ]
type RandomRM m = (Integer, Integer) -> m Integer
primeMillerRabinWith :: Monad m => RandomRM m -> Integer -> m Bool
primeMillerRabinWith randomRM n = do
let nMinus1 = n-1
(s,d) = nMinus1 `factorBy` 2
liftM (all id) . replicateM 10 $ do
a <- randomRM (2, nMinus1)
let x = (a^d) `mod` n
let xs = take s $ iterate (\x -> (x^2) `mod` n) x
return $ x == 1 || any (== nMinus1) xs
probableMersennePrimesWith :: Monad m => RandomRM m -> m [Integer]
probableMersennePrimesWith randomRM = filterM (primeMillerRabinWith randomRM) mersennes
probableMersennePrimesPure :: RandomGen g => g -> [Integer]
probableMersennePrimesPure = evalState . probableMersennePrimesWith $ state . randomR
probableMersennePrimesIO :: IO [Integer]
probableMersennePrimesIO = probableMersennePrimesWith $ randomRIO
所有其他答案都很好。但是,我认为解决这个问题最简单的方法是惰性IO,值得考虑。我还认为在这种特殊情况下,惰性IO是无害的,因为它不涉及系统资源(文件句柄等)
您只需要为惰性IO重新定义一个特殊的filterM
import System.IO.Unsafe (unsafeInterleaveIO)
filterMIO :: (a -> IO Bool) -> [a] -> IO [a]
filterMIO p = go
where
go [] = return []
go (x:xs) = do
xs' <- unsafeInterleaveIO (go xs)
b <- p x
return $ if b then (x:xs') else xs'
probableMersennePrimes :: IO [Integer]
probableMersennePrimes = filteMIO primeMillerRabin mersennes
import System.IO.Unsafe(unsafeInterleaveIO)
filterMIO::(a->IO Bool)->[a]->IO[a]
filterMIO p=go
哪里
go[]=return[]
go(x:xs)=do
为什么这是IO?素数检查器不应该是纯的吗?这是一个概率素数检查器。好的。如果IO是必要的,我会选择@cirdec-answer。
import System.IO.Unsafe (unsafeInterleaveIO)
filterMIO :: (a -> IO Bool) -> [a] -> IO [a]
filterMIO p = go
where
go [] = return []
go (x:xs) = do
xs' <- unsafeInterleaveIO (go xs)
b <- p x
return $ if b then (x:xs') else xs'
probableMersennePrimes :: IO [Integer]
probableMersennePrimes = filteMIO primeMillerRabin mersennes