使用IO在Haskell中创建无限列表
编辑 我试图写一个算法,生成一个(无限)梅森素数列表。我有一个算法(Rabin Miller),根据算法是否认为数字是素数,返回IO布尔。这个算法叫做rabinMiller,它需要两个参数,第一个是表示列表安全性的整数,第二个是我们提交给素性测试的数字 我想索引所有素数(称为素数)的列表,对于素数中的每个p,检查rabinMiller是否认为2^p-1是素数。如果是,我们将向列表提交2^p-1 我现在得到的是:使用IO在Haskell中创建无限列表,haskell,Haskell,编辑 我试图写一个算法,生成一个(无限)梅森素数列表。我有一个算法(Rabin Miller),根据算法是否认为数字是素数,返回IO布尔。这个算法叫做rabinMiller,它需要两个参数,第一个是表示列表安全性的整数,第二个是我们提交给素性测试的数字 我想索引所有素数(称为素数)的列表,对于素数中的每个p,检查rabinMiller是否认为2^p-1是素数。如果是,我们将向列表提交2^p-1 我现在得到的是: rbMersenneGen :: Integer -> IO(IO [Inte
rbMersenneGen :: Integer -> IO(IO [Integer])
rbMersenneGen k = do return $ rbMersenneGens 0 k
rbMersenneGens :: Int -> Integer -> IO [Integer]
rbMersenneGens x k =
let n = primes!!x
m = (2^n) - 1
in do
prim <- rabinMiller k m
if prim then
m:rbMersenneGens (x + 1) k
else
rbMersenneGens (x + 1) k
rbMersenneGen::Integer->IO(IO[Integer])
rbMersenneGens k=返回$rbMersenneGens 0 k
rbMersenneGens::Int->Integer->IO[Integer]
rbMersenneGens x k=
让n=素数!!x
m=(2^n)-1
在做
prim您在rbMersenneGens
中有一个do块。do块的结果始终与其中的内容在同一个monad中。由于在IO
monad中调用rabinMiller
inside,do块的结果也在IO
monad中。但是您已经声明,rbMersenneGens
返回一个[Integer]
,它与推导的类型不匹配;我们只需要稍微调整一下rbMersenneGens
的定义。我还将对函数进行一点重构
rbMersenneGen :: Integer -> IO [Integer]
rbMersenneGen k = rbMersenneGens 0 k
rbMersenneGens :: Int -> Integer -> IO [Integer]
rbMersenneGens x k =
let n = primes!!x
m = (2^n) - 1
in do
prim <- rabinMiller k m
-- We call rmMersenneGens the same way in either case;
-- the only difference is which function we apply to the result
(if prim then (m:) else id) (rbMersenneGens (x+1) k)
因为我们仍然试图将prim
视为Bool
而不是IO Bool
,但这确实:
rbMersenneGens :: Int -> Integer -> IO [Integer]
rbMersenneGens x k =
let n = primes!!x
m = (2^n) - 1
prim = rabinMiller k m
in (bool id (m:)) <$> prim <*> (rbMersenneGens (x+1) k)
rbMersenneGens::Int->Integer->IO[Integer]
rbMersenneGens x k=
让n=素数!!x
m=(2^n)-1
prim=拉宾米勒k m
in(bool-id(m:))prim(rbMersenneGens(x+1)k)
如果
与一个IO Bool一起工作,我们就不能使,但我们可以将Bool提升到一个。事实上,我们只需要将IO
视为应用程序
,而不是单子
。我们正在用fmap
(以中缀形式
)替换=
。您必须执行:如果是prim,则执行xs,问题是Rabin Miller使用随机数。哈斯克尔对随机数有一个问题,因为它们本质上是不纯的。如果它是Rabin Miller的实现,那么需要重写它,将随机种子作为参数。或者使用不同的素性测试。是的。我认为OP可能会陷入错误,但如果我让它返回[IO Integer]
和rbMersenneGen
IO[IO Integer]
则会发生相同的错误(还有两个错误)。声明的返回值意味着do
表达式正在列表monad中运行,而prim
需要是Bool
,因为它与if
表达式一起使用。这意味着rabinMiller
将需要返回[Bool]
值,但它返回IO Bool
@Mal。在编译器关闭之前,您不能向它抛出类型。您需要了解rabinMiller
(以及IO
)的IO Bool
结果类型的一般含义。@SebastianRedl,在编译器关闭之前抛出类型是迄今为止我发现的使用多态递归处理非规则数据类型的最佳方法。当然,这可能只是意味着我的大脑不够强大。难道不会永远循环(IO是一个严格的应用程序)吗?非常感谢!这成功了!只有(m:)
和id
需要切换(在最后一行),因为bool
行为怪异。如果我运行
rbmersennegenk,它永远不会返回任何东西。。。但是我可以通过制作rbMersenneGens n=return[]
来解决这个问题,因为我没有仔细阅读bool
的描述。
rbMersenneGens :: Int -> Integer -> IO [Integer]
rbMersenneGens x k =
let n = primes!!x
m = (2^n) - 1
prim = rabinMiller k m
in (bool id (m:)) <$> prim <*> (rbMersenneGens (x+1) k)