Haskell sqrt类型错误

时间:2013-08-31 10:53:58

标签: haskell types type-conversion factors

好的,所以我正在尝试编写一个有效检测给定Int的所有因子的Haskell函数。根据{{​​3}}中给出的解决方案,我得到了以下内容:

-- returns a list of the factors of n
factors         ::  Int -> [Int]
factors n       =   sort . nub $ fs where
                        fs  =   foldr (++) [] [[m,n `div` m] | m <- [1..lim+1], n `mod` m == 0]
                        lim =   sqrt . fromIntegral $ n

可悲的是,GHCi告诉我包含No instance for (Floating Int)等的行中有lim =等。

我已阅读this question,建议的解决方案在直接输入GHCi时有效 - 它允许我在sqrt上调用Int。但是,当看起来完全相同的代码放在我的函数中时,它就不再起作用了。

我对Haskell比较陌生,所以我非常感谢你的帮助!

2 个答案:

答案 0 :(得分:4)

检查sqrt

的类型时
Prelude> :t sqrt 
sqrt :: Floating a => a -> a

它需要一个浮点数。它在ghci中不起作用。您可能尝试在数字上调用它,ghci会将类型推断为Float。

Prelude> let a = 1 :: Int

Prelude> sqrt a

<interactive>:5:1:
    No instance for (Floating Int) arising from a use of `sqrt'
    Possible fix: add an instance declaration for (Floating Int)
    In the expression: sqrt a
    In an equation for `it': it = sqrt a

现在回到你的代码。问题出在表达式[1 .. lim + 1]中。算术序列只能应用于Enum a => a类型的值。由于lim属于Floating a => a类型,因此您需要通过Integral a => aceiling将其转换回floor。仅供参考,Integral类实例也将类型约束为具有Enum实例。

答案 1 :(得分:1)

你需要从积分转换为(n :: Int)到Double。然后你需要从sqrt得到的Double转换回Int。你将需要四舍五入,因为你使用(lim + 1)我可以看到你需要使用地板向下舍入:

isqrt :: Int -> Int
isqrt i = let d :: Double
              d = fromIntegral i
          in floor (sqrt d)

现在,您可以在代码中使用此代替sqrt。