用于查找素数的 Haskell 列表理解

发布于 2024-11-09 06:58:58 字数 797 浏览 0 评论 0原文

我试图使用列表推导式尽可能简洁地找到小于某个整数 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

白色秋天 2024-11-16 06:58:58

我在以下方面取得了一些进展:

primes :: Integral a => a -> [a]  
primes 2 = [2]  
primes n = 2:[i | i <- [3,5..n], all (\k -> if (mod i k /= 0) then True else False) 
                                     (primes (isqrt i))]

是否有更短的方法来编写 lambda 谓词?

编辑:是的,有,感谢评论中的评论!

primes :: Integral a => a -> [a]  
primes 2 = [2]  
primes n = 2:[i | i <- [3,5..n], all ((/= 0) . mod i) (primes (isqrt i))]

I made some progress with the following:

primes :: Integral a => a -> [a]  
primes 2 = [2]  
primes n = 2:[i | i <- [3,5..n], all (\k -> if (mod i k /= 0) then True else False) 
                                     (primes (isqrt i))]

Is there a shorter way to write the lambda predicate?

edit: Yes, there is, thanks to the remarks in the comments!

primes :: Integral a => a -> [a]  
primes 2 = [2]  
primes n = 2:[i | i <- [3,5..n], all ((/= 0) . mod i) (primes (isqrt i))]
音盲 2024-11-16 06:58:58

您的代码

primes n = [i | i <- [1,3..n], mod i k /= 0 
              | k <- primes (isqrt i)]

被解释为并行列表理解;即,不是以通常的嵌套方式组合两个生成器,而是并行组合:

primes n = [i | (i,k) <- zip [i | i <- [1,3..n], mod i k /= 0]
                                    -- not in scope: k ^
                             [k | k <- primes (isqrt i)] ]
                                  -- not in scope: i ^

相反,为了表达您的意图,它可以写成

primes 1 = []
primes n = 2:[i | i <- [3,5..n], and [mod i k /= 0 | k <- primes (isqrt i)]]

在列表理解中具有列表理解 - 但是作为守卫的一部分,而不是发电机的一部分。函数 and :: [Bool] -> Bool 使这成为可能。


顺便说一句,为每个新候选i递归调用primes会使其运行缓慢,并且运行时间增长得太快,经验

 > length $ primes 10000     -- => 1229    (0.50 secs)

 > length $ primes 20000     -- => 2262    (1.40 secs)

 > logBase (2262/1229) (1.4/0.5)      -- => 1.6878      ~ n^1.69

 > length $ primes 40000     -- => 4203    (4.07 secs)

 > logBase (4203/2262) (4.07/1.4)     -- => 1.7225      ~ n^1.72

最佳试除法通常运行在 ~ n1.4..1.45,基于列表的埃拉托色尼筛选 ~ n1.2..1.25 并且,如果最佳实施可变数组,位于 ~ n1.0..1.1(其中 n 为生成的素数数量, 不是上限)。

your code,

primes n = [i | i <- [1,3..n], mod i k /= 0 
              | k <- primes (isqrt i)]

is interpreted as parallel list comprehension; i.e. instead of combining the two generators in the usual nested fashion, they are combined in parallel:

primes n = [i | (i,k) <- zip [i | i <- [1,3..n], mod i k /= 0]
                                    -- not in scope: k ^
                             [k | k <- primes (isqrt i)] ]
                                  -- not in scope: i ^

Instead, to express what you intended, it can be written as

primes 1 = []
primes n = 2:[i | i <- [3,5..n], and [mod i k /= 0 | k <- primes (isqrt i)]]

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 candidate i makes it run slow, with run times growing too fast, empirically:

 > length $ primes 10000     -- => 1229    (0.50 secs)

 > length $ primes 20000     -- => 2262    (1.40 secs)

 > logBase (2262/1229) (1.4/0.5)      -- => 1.6878      ~ n^1.69

 > length $ primes 40000     -- => 4203    (4.07 secs)

 > logBase (4203/2262) (4.07/1.4)     -- => 1.7225      ~ n^1.72

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).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文