Haskell 素数函数不起作用
过去几天我开始学习 Haskell,但我在这段代码上遇到了麻烦。我正在尝试创建一个函数,该函数将生成一个素数列表,给定初始列表(至少包含 2)、最大列表长度、当前除数的索引(应从 1 开始,通过将当前数字除以所有数字进行测试)到目前为止的素数)和当前要测试的数字(奇数)。
我知道它不是很优雅或高效,但此代码无法编译或运行,因此我想在优化之前先修复它。尽管对此的建议也很酷。
primes = [2,3,5,7,11,13]
genPrimes primes max curDiv curTest
| length primes >= max = primes
| primes !! curDiv > floor . sqrt curTest = genPrimes (primes ++ [curTest]) max 1 (curTest + 2)
| curTest `mod` primes !! curDiv == 0 = genPrimes primes max 1 (curTest + 2)
| curTest `mod` primes !! curDiv /= 0 = genPrimes primes max (curDiv + 1) curTest
当我尝试编译上面的代码时出现以下错误:
Couldn't match expected type `a0 -> c0' with actual type `Integer'
Expected type: [a0 -> c0]
Actual type: [Integer]
In the first argument of `genPrimes', namely `primes'
In the expression: genPrimes primes 50 1 15
I've started learning Haskell in the last couple of days and I'm having trouble with this piece of code. I'm trying to make a function that will generate a list of primes given an initial list (contains at least 2), a maximum list length, the index of the current divisor (should start at 1, tests by dividing current number by all primes so far) and the current number to test (an odd number).
I know it's not very elegant or efficient but this code won't compile or run so I'd like to fix it first before optimizing. Although suggestions on that would be cool too.
primes = [2,3,5,7,11,13]
genPrimes primes max curDiv curTest
| length primes >= max = primes
| primes !! curDiv > floor . sqrt curTest = genPrimes (primes ++ [curTest]) max 1 (curTest + 2)
| curTest `mod` primes !! curDiv == 0 = genPrimes primes max 1 (curTest + 2)
| curTest `mod` primes !! curDiv /= 0 = genPrimes primes max (curDiv + 1) curTest
I get the following error when I try to compile the above code:
Couldn't match expected type `a0 -> c0' with actual type `Integer'
Expected type: [a0 -> c0]
Actual type: [Integer]
In the first argument of `genPrimes', namely `primes'
In the expression: genPrimes primes 50 1 15
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
至少你的代码应该是
然后你重新组织它(抽象出对每个候选数字执行的测试,作为
noDivs
函数):你重写
noDivs
然后 您注意到
go
只是过滤数字,以便通过noDivs
测试:但这还不起作用,因为
theTest
需要通过primes
(全新的素数,因为它们被发现)到noDivs
,但我们正在构建这个whole_primes
列表(如取max(primes ++ ...)
),那么是否存在恶性循环呢?不,因为我们只测试一个数字的平方根:这现在有效。但最后,现在
genPrimes
没有什么特别的,它只是对take
的美化调用,并且初始primes
列表实际上可以缩小,所以我们get(稍微更改一下noDivs
的参数排列,以使其接口更通用):全局
primes
列表现在无限期定义(即“无限”)。 下一步是实现素数的连续平方之间的因子列表的长度测试依据将是相同的,每个新段增加 1。 然后,将所有因素预先作为全局的前缀(已知长度)primes
列表中,我们可以直接生成它们的倍数(因此每个数字都是从它的质因数生成的),而不是测试每个数字是否是其中任何一个的倍数以下主要因素按顺序计算其平方根。At the very least your code should be
Then you reorganize it thus (abstracting away the tests performed for each candidate number, as the
noDivs
function):then you rewrite
noDivs
asthen you notice that
go
just filters numbers through such that pass thenoDivs
test:but this doesn't work yet, because
theTest
needs to passprimes
(whole new primes as they are being found) tonoDivs
, but we are building thiswhole_primes
list (astake max (primes ++ ...)
), so is there a vicious circle? No, because we only test up to the square root of a number:This is working now. But finally, there's nothing special in
genPrimes
now, it's just a glorified call totake
, and initialprimes
list can actually be shrunk, so we get (changing the arguments arrangement fornoDivs
a little, to make its interface more general):The global
primes
list is indefinitely defined now (i.e. "infinite"). Next step is to realize that between the consecutive squares of primes the length of the list of factors to test by will be the same, incrementing by 1 for each new segment. Then, that having all the factors upfront as the prefix (of known length) of the globalprimes
list, we can directly generate their multiples (thus each being generated just from its prime factors), instead of testing each number whether it is a multiple of any one of the prime factors below its square root, in sequence.您已经将 ':' 的参数颠倒了:标量向左移动,或者您可以创建一个单例列表并连接:
You've got the arguments to ':' reversed: the scalar goes to the left, or you can make a singleton list and concatenate:
ja.已经给出了正确的答案,但你的解决方案不是很惯用。这是生成无限素数列表的简单方法:
primes
很容易理解,它将 2 定义为素数,并检查所有后续奇数是否是素数。isPrime
有点复杂:首先我们取所有小于或等于n
的平方根的素数。然后我们检查是否将n
除以所有这些素数,我们没有提示等于 0。isPrime
引用回primes
,但是这个没问题,因为 Haskell 很懒,而且我们的检查从来不需要“太多”素数。列表
primes
是无限的,但您可以编写类似于take 10 primes
的内容。请注意,此代码有其自身的问题,请参阅 http://www. cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf
ja. gave already the correct answer, but your solution isn't very idiomatic. Here is an easy way to generate an infinite list of primes:
primes
is easy to understand, it defines 2 as prime, and inspects all following odd numbers if they are prime.isPrime
is a little bit more complicated: First we take all primes smaller or equal to the square root ofn
. Then we check if we dividen
by all of these primes that we have no reminder equal to 0.isPrime
refers back toprimes
, but this is no problem as Haskell is lazy, and we never need "too much" primes for our check.The list
primes
is infinite, but you can just write something liketake 10 primes
.Note that this code has its own problems, see http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf