用于查找素数的 Haskell 列表理解
我试图使用列表推导式尽可能简洁地找到小于某个整数 n 的所有素数。我正在学习 Haskell,这只是一个练习。我想写这样的东西:
isqrt :: Integral a => a -> a
isqrt = floor . sqrt . fromIntegral
primes :: Integral a => a -> [a]
primes n = [i | i <- [1,3..n], mod i k /= 0 | k <- primes (isqrt i)]
这当然行不通。有没有办法在列表理解中进行列表理解?
这是我收到的错误:
exercise-99-1.hs:138:39: Not in scope: `k'
exercise-99-1.hs:138:46:
Illegal parallel list comprehension: use -XParallelListComp
exercise-99-1.hs:138:68: Not in scope: `i'
但是 - 我真的没想到语法是合法的 :-)
目的是尽可能直接翻译:" primes n
=小于 n
的奇数整数 i
集合,使得 i
不能被任何 k
整除,对于所有 <集合中的 code>k:primes (isqrt i)
" - 或多或少。 (我希望我猜对了?)
谢谢!
I'm trying to find all the primes less than some integer n
as concisely as possible, using list comprehensions. I'm learning Haskell, and this is just an exercise. I'd like to write something like:
isqrt :: Integral a => a -> a
isqrt = floor . sqrt . fromIntegral
primes :: Integral a => a -> [a]
primes n = [i | i <- [1,3..n], mod i k /= 0 | k <- primes (isqrt i)]
which of course doesn't work. Is there a way to have a list comprehension inside a list comprehension?
Here is the error I'm getting:
exercise-99-1.hs:138:39: Not in scope: `k'
exercise-99-1.hs:138:46:
Illegal parallel list comprehension: use -XParallelListComp
exercise-99-1.hs:138:68: Not in scope: `i'
BUT - I wasn't really expecting the syntax to even be legit :-)
The intent was to translate as directly as possible: " primes n
= the set of odd integers i
less than n
such that i
is not divisible by any k
, for all k
in the set: primes (isqrt i)
" - more or less. (I hope I got that right?)
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我在以下方面取得了一些进展:
是否有更短的方法来编写 lambda 谓词?
编辑:是的,有,感谢评论中的评论!
I made some progress with the following:
Is there a shorter way to write the lambda predicate?
edit: Yes, there is, thanks to the remarks in the comments!
您的代码
被解释为并行列表理解;即,不是以通常的嵌套方式组合两个生成器,而是并行组合:
相反,为了表达您的意图,它可以写成
在列表理解中具有列表理解 - 但是作为守卫的一部分,而不是发电机的一部分。函数
and :: [Bool] -> Bool
使这成为可能。顺便说一句,为每个新候选
i
递归调用primes
会使其运行缓慢,并且运行时间增长得太快,经验:最佳试除法通常运行在 ~ n1.4..1.45,基于列表的埃拉托色尼筛选 ~ n1.2..1.25 并且,如果最佳实施可变数组,位于 ~ n1.0..1.1(其中 n 为生成的素数数量, 不是上限)。
your code,
is interpreted as parallel list comprehension; i.e. instead of combining the two generators in the usual nested fashion, they are combined in parallel:
Instead, to express what you intended, it can be written as
thus having a list comprehension inside a list comprehension - but as part of a guard, not generator. The function
and :: [Bool] -> Bool
makes this possible.Incidentally, calling
primes
recursively for each new candidatei
makes it run slow, with run times growing too fast, empirically:Optimal trial division usually runs at ~ n1.4..1.45, list-based sieve of Eratosthenes at ~ n1.2..1.25 and, if optimally implemented on mutable arrays, at ~ n1.0..1.1 (with n the number of primes produced, not the upper limit).