比较积分值和浮点值

Shr*_*rat 3 haskell prime-factoring

所以,我正在学习Haskell,并经常陷入类型/类型相关的错误.一些非常明显的愚蠢错误,以及一些让我觉得haskell的错误对我来说不合适.无论如何,我有这段代码......

pfactors' ps n
    | p > (sqrt n) = []
    | m == 0 = p : (pfactors' ps q)
    | otherwise = pfactors' (tail ps) n where
        p = head ps
        (q, m) = divMod n p

pfactors = pfactors' primes

main = print $ pfactors 14
Run Code Online (Sandbox Code Playgroud)

(一些背景:pfactors函数应该接受一个数字并返回一个素数列表,它是给定数字的主要因子.primes是素数的无限列表)

这给了我这个错误:

p47.hs:10:11:
    Ambiguous type variable `a' in the constraints:
      `Floating a' arising from a use of `pfactors'' at p47.hs:10:11-26
      `Integral a' arising from a use of `primes' at p47.hs:10:21-26
    Possible cause: the monomorphism restriction applied to the following:
      pfactors :: a -> [a] (bound at p47.hs:10:0)
    Probable fix: give these definition(s) an explicit type signature
                  or use -XNoMonomorphismRestriction
Run Code Online (Sandbox Code Playgroud)

现在我明白这是部件的一个问题p < (sqrt n),因为它是唯一与之相关的部分Floating.如果我改变它,p < n一切正常,我得到了正确的答案.但我真的想用平方根来检查一下,那我该怎么做呢?

顺便说一句,这不是功课,如果感觉像是,我试图解决projecteuler.net上的第47个问题

谢谢你的帮助.

并且,请不要给我解决所述项目的euler问题,我想尽可能多地自己做:).谢谢.

Joe*_*ams 6

你的问题是......好吧......你无法比较积分和浮点值:-)你必须明确指出整数和浮点数之间的转换.该sqrt :: (Floating a) => a -> a函数适用于浮点数,但您主要处理整数,因此您无法免费使用它.尝试这样的事情:

pfactors' ps n
    | p > (floor $ sqrt $ fromIntegral n) = []
    | m == 0 = p : (pfactors' ps q)
    | otherwise = pfactors' (tail ps) n where
        p = head ps
        (q, m) = divMod n p
Run Code Online (Sandbox Code Playgroud)

在这里,我们使用fromIntegral :: (Integral a, Num b) => a -> b从整数转换为其他东西,允许我们使用它作为参数sqrt.然后,我们说floor将我们的浮点值转换回整数(注意这会向下舍入!).

其次,我建议养成在顶级声明中添加类型签名的习惯.它不仅可以让你更好地掌握语言,而且如果你不这样做,你可能会违反单态限制.


Car*_*arl 5

我想提供一些关于正在发生的事情的额外说明,即使已经提供了解决方案.

特别是,类型类不是类型.您不能拥有积分值或浮动值.那些不是类型,它们是类型类.这不像面向对象的子类型.

Integral a => a -> a -> a这样的签名并不意味着"一个带有两个Integral参数的函数,并返回一些Integral值." 它表示"一个函数,它接受两个类型为a的值,并返回一个类型为a的值.另外,键入a必须是Integral的一个实例." 两者之间的差异很大.记住参数和返回值都是相同的类型非常重要."a"不能在类型签名中改变其含义.

那么,这意味着什么?

嗯,首先,没有先验要求类型不能是Integral和Floating的实例.如果你有这样的类型,则不需要转换.但是,每个类型类的语义含义使得单个类型很难以有意义的方式成为两者的实例.

其次,在谈论类型类时,你应该更加小心.它们与面向对象的子类型根本不同.由于概念上的差异,也存在术语上的差异.准确掌握术语有助于理解差异,并与他人沟通.

那么我该怎么说这个问题呢?像"如何将整数转换为浮动和返回的实例?我需要使用sqrt :: Floating a => a -> a函数,并将其结果与Integer值进行比较."