好的,所以我正在尝试编写一个有效检测给定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比较陌生,所以我非常感谢你的帮助!
答案 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 => a
或ceiling
将其转换回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。