Haskell素数测试
我是 Haskell 的新手,我正在尝试一下:
isPrime :: Integer->Bool
isPrime x = ([] == [y | y<-[2..floor (sqrt x)], mod x y == 0])
我有几个问题。
- 为什么当我尝试加载 .hs 时,WinHugs 说:定义
isPrime
需要(Floating Integer, RealFrac Integer)
实例? - 当解释器在正确的集合中找到一个元素时,它会立即停止还是计算所有集合?我想你知道我的意思。
对不起我的英语。
I'm new to Haskell, and I'm trying a bit:
isPrime :: Integer->Bool
isPrime x = ([] == [y | y<-[2..floor (sqrt x)], mod x y == 0])
I have a few questions.
- Why when I try to load the .hs, WinHugs say: Instances of
(Floating Integer, RealFrac Integer)
required for definition ofisPrime
? - When the interpreter finds one element in the right set, it immediately stops or it computes all the set? I think you know what I mean.
Sorry about my english.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
1) 问题是
sqrt
的类型为(Floating a) =>;一个-> a
,但您尝试使用整数作为参数。因此,您必须首先将整数转换为浮点数,例如通过编写sqrt (fromIntegral x)
2) 我认为 == 没有理由不应该偷懒,但为了测试空集合,您可以使用 null 函数(这绝对是惰性的,因为它适用于无限列表):
但是为了获得更惯用的解决方案,请将问题分解为更小的子问题。首先,我们需要一个包含 y*y <= x 的所有元素 y 的列表:
然后我们只需要整除 x 的元素:
然后我们需要检查该列表是否为空:
如果这对你来说看起来很 lispy,请替换一些括号带有 $
为了更加清晰,您可以“外包” lambda:
您可以通过将 null $ 过滤器替换为 not $ any 来使其几乎“人类可读”:
1) The problem is that
sqrt
has the type(Floating a) => a -> a
, but you try to use an Integer as argument. So you have to convert your Integer first to a Floating, e.g. by writingsqrt (fromIntegral x)
2) I see no reason why == shouldn't be lazy, but for testing for an empty collection you can use the
null
function (which is definitely lazy, as it works on infinite lists):But in order to get an more idiomatic solution, break the problem into smaller sub-problems. First, we need a list of all elements y with y*y <= x:
Then we need only the elements that divide x:
Then we need to check if that list is empty:
And if this looks to lispy to you, replace some of the parens with $
For additional clarity you can "outsource" the lambdas:
You can make it almost "human readable" by replacing null $ filter with not $ any:
因为
sqrt
的类型为Floating a =>;一个->一个。这意味着输入必须是
Floating
类型,并且输出也将是相同的类型。换句话说,x
需要是Floating
类型。但是,您将x
声明为Integer
类型,它不是Floating
类型。此外,floor
需要RealFrac
类型,因此x
也需要是该类型。错误消息建议您通过将
Integer
设为Floating
类型(通过定义一个实例Floating Integer
)来解决该问题(对于RealFrac
)。当然,在这种情况下这不是正确的方法。相反,您应该使用
fromIntegral
将x
转换为Real
(这是Floating
和的实例) RealFrac
),然后将其赋予sqrt
。是。 == 看到右操作数至少有一个元素,它知道它不等于
[]
,因此返回False
。话虽如此,
null
是一种比[] ==
更惯用的检查列表是否为空的方法。Because
sqrt
has the typeFloating a => a -> a
. This means the input has to be aFloating
type and the output will be the same type. In other wordsx
needs to be aFloating
type. However you declaredx
to be of typeInteger
, which is not aFloating
type. In additionfloor
needs aRealFrac
type, sox
needs to be that as well.The error message suggests that you fix that by making
Integer
aFloating
type (by defining an instanceFloating Integer
(and the same forRealFrac
).Of course this is not the correct approach in this case. Rather you should use
fromIntegral
to convertx
to aReal
(which is an instance ofFloating
andRealFrac
) and then give that tosqrt
.Yes. As soon as
==
sees that the right operand has at least one element, it knows it is not equal to[]
and thus returnsFalse
.That being said,
null
is a more idiomatic way to check whether a list is empty than[] ==
.关于第二点,就停止了,例如:
Returns
False
Regarding the second point, it stops, for example:
Returns
False
Landei 的解决方案很棒,但是,如果您想要更高效的 1 实现,我们有(感谢 BMeph):
“效率”来自于常数素数的使用。它以两种方式改进了搜索:
请注意,
sieve
值只是一个递归表,其中表示该列表是素数,并将其添加到其中。对于其余列表,如果没有
组成数字的列表中已有的其他值,那么它也是素数
possible
是所有可能的素数的列表,因为所有可能的素数都在形成 6*k-1 或 6*k-1(2 和 3 除外)
同样的规则也适用于
shortCircuit
,以快速摆脱计算脚注(DF
)
1 这仍然是一种寻找素数的极其低效的方法。如果您需要大于几千的素数,请不要使用试除法,而应使用筛子。还有几个更多 在 hackage 上实现高效。
Landei's solution is great, however, if you want a more efficient¹ implementation we have (thanks to BMeph):
The 'efficiency' comes from the use of constant primes. It improves the search in two ways:
note that the
sieve
value is simply a recursive table, where says the head ofthe list is prime, and adds it to it. For the rest of the lists if there is no
other value already in the list that composes the number then its also prime
possible
is list of all possible primes, since all possible primes are in theform 6*k-1 or 6*k-1 except 2 and 3
The same rule is applied for
shortCircuit
too to quickly bail out of calculationsFootnote by D.F.
¹ It's still a terribly inefficient way to find primes. Don't use trial division if you need primes larger than a few thousand, use a sieve instead. There are several far more efficient implementations on hackage.
isPrime 32
然后它将延迟计算表达式。PS 你的 isPrime 实现不是最好的实现!
isPrime 32
then it will lazily compute the expression.PS your isPrime implementation is not the best implementation!