1

好的,所以我正在尝试编写一个 Haskell 函数,它可以有效地检测给定Int. 根据这个问题中给出的解决方案,我得到了以下信息:

-- 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 告诉我在包含etc. 等No instance for (Floating Int)的行中有。lim =

我已经阅读了这个答案,并且建议的解决方案在直接输入 GHCi 时有效 - 它允许我sqrt调用Int. 但是,当在我的函数中放置看起来完全相同的代码时,它就会停止工作。

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

4

2 回答 2

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]。算术序列只能应用于 type 的值Enum a => a。由于limis 的类型Floating a => a,您需要Integral a => a通过使用ceilingor将其转换回floor。仅供参考,Integral类实例也约束类型具有Enum实例。

于 2013-08-31T11:05:35.070 回答
2

您确实需要 fromIntegral 将 (n :: Int) 转换为 Double。然后,您需要从 sqrt 获得的 Double 转换回 Int。你需要四舍五入,因为你使用 (lim+1) 我可以看到你需要向下舍入,使用 floor:

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

现在您可以在代码中使用它而不是 sqrt。

于 2013-08-31T11:04:17.397 回答