我正在学习Haskell,我正在尝试编写一个函数来返回一个数字的因子列表。这就是我所拥有的:
factors :: Int -> [Int]
factors n = [x | x <- [2..s], n `mod` x == 0]
where s = floor (sqrt n)
当我尝试在ghci
中加载模块时,我收到两个错误,
p003.hs:3:14:
No instance for (RealFrac Int)
arising from a use of `floor' at p003.hs:3:14-27
Possible fix: add an instance declaration for (RealFrac Int)
In the expression: floor (sqrt n)
In the definition of `s': s = floor (sqrt n)
In the definition of `factors':
factors n = [x | x <- [2 .. s], n `mod` x == 0]
where
s = floor (sqrt n)
p003.hs:3:21:
No instance for (Floating Int)
arising from a use of `sqrt' at p003.hs:3:21-26
Possible fix: add an instance declaration for (Floating Int)
In the first argument of `floor', namely `(sqrt n)'
In the expression: floor (sqrt n)
In the definition of `s': s = floor (sqrt n)
Failed, modules loaded: none.
有什么建议吗?
答案 0 :(得分:10)
参数的类型为Int
,因此您无法为其计算平方根。您需要先将其转换为浮点类型,您可以使用fromIntegral。与其他一些语言不同,Haskell不会自动将整数提升为浮点数(也不会进行任何其他自动类型转换)。
所以将sqrt n
更改为sqrt (fromIntegral n)
。
答案 1 :(得分:9)
sqrt
函数的类型是
sqrt :: (Floating a) => a -> a
您可以在ghci中输入:t sqrt
来查看此内容。
Int
不是Floating
的实例,这就是您看到第二个错误的原因。
第一个错误的原因是一样的;检查:t floor
会显示类型为:
floor :: (RealFrac a, Integral b) => a -> b
该函数需要RealFrac
的实例,并且您提供的是Int
。
键入:info RealFrac
或:info Floating
表明两者都没有Int
的实例,这就是错误主体所说的原因
没有实例... Int
解决这个问题的方法是确保类型正确;他们必须是正确类型的成员。
执行此操作的一种简单方法是使用fromIntegral
函数,:t
显示的类型为:
fromIntegral :: (Integral a, Num b) => a -> b
使用fromIntegral
是必要的,因为传入类型为Int
,但函数floor
和sqrt
对RealFrac
和Floating
类型进行操作, 分别。
这是允许的,因为正如您从类型签名中看到的那样,fromIntegral
会返回Num
的实例,其中包含RealFrac
和Floating
类型。您可以通过在ghci中输入:info Num
和:info Float
并查看输出来说服自己。
对您的程序进行更改将得到以下最终结果,该结果可以按您的要求运行:
factors :: Int -> [Int]
factors n = [x | x <- [2..s], n `mod` x == 0]
where s = floor (sqrt $ fromIntegral n)
有关正确了解正在发生的事情的两个很好的资源是关于Type Classes和Numbers的Haskell教程部分。