整数的haskell类型签名

时间:2012-01-13 04:13:58

标签: haskell

我想写一个函数来判断一个给定的整数是否为素数,我应该使用类型签名

  isPrime :: Int -> Bool

  isPrime :: (Integral a) => a -> Bool

区别是什么?是否有特别的理由选择其中一个?
如果是这样,我应该在哪种情况下分别使用这两种?

3 个答案:

答案 0 :(得分:11)

类型Int -> Bool表示您的函数对Int类型的值进行操作,这些值是大小限制的整数(我相信,最大大小取决于机器)。

类型(Integral a) => a -> Bool表示您的函数对任何类型的值进行操作,该类型具有Integral类型类的实例 - 即表现的类型喜欢以特定方式整数。在具体类型上选择它的主要原因是创建一个更通用的功能。

当您需要在其他上下文中使用类似整数的类型时,使用Integral的通用表单最有用 - 一个很好的示例是标准库失败的地方所以,例如像replicate :: Int -> a -> [a]这样的函数。对于某些特定类似整数类型的代码,为了自己的目的,希望将该类型与replicate一起使用,因此需要首先转换为Int,或者从{{1}导入genericReplicate }。

在您的情况下,您可能需要考虑的是类型Data.List,它表示任意大小的整数。由于您的主要目标是计算,因此支持任意整数类型的价值较小。

如果内存为我服务,标准库中Integer的唯一实例无论如何都是IntegralInt。 (编辑:正如Hammar在评论中提醒我的那样,IntegerData.Int中也存在固定大小类型的实例。还有{{1}等外来类型但我故意无视这些。)

答案 1 :(得分:4)

我会推荐签名

isPrime :: Integer -> Bool

签名isPrime :: Int -> Bool将排除对大数字的快速测试,因为那些测试通常会溢出(技术上也是Integer也是如此,至少在integer-gmp提供的版本中,但在重要之前你很可能会记忆 long ,所以我们可以保持无限Integer类型的虚构。

类型isPrime :: Integral a => a -> Bool将是任何可行实现的谎言。对于类型建模Integral,可以有一个Z[sqrt(2)]的实例(虽然对于这样的类型toInteger会不忠实),对于这样的类型,2不会是素数,怎么会一个用通用测试检测到它?

或者考虑对因子环Z/(n)建模的有限类型。此类型的Ord实例与算术不兼容,但我们已经为Int等提供了此类实例。例如,在Z(6) = {0,1,2,3,4,5}中,primes将为2, 3和4(注意,它们都不是irreducible,2 = 4 * 2,3 = 3 * 3,4 = 2 * 2)。

所以唯一有意义且可行的测试是,#34;它是一个理性(或自然)素数,它的值恰好在类型的范围内?"。在isPrime :: Integer -> Bool类型中捕获(尽可能好,而不牺牲太多速度),在适当的时候与toInteger组合。

答案 2 :(得分:1)

许多素性测试都是概率性的并且需要随机数,所以至少在最低级别他们会有这样的类型签名:

seemsPrime :: (Integral a) => a -> [a] -> Bool

Integral约束似乎是合理的,因为通常你不需要具体类型,只需要rem之类的操作。