这不是重复的问题。请阅读以下内容......
我正在声明以下功能:
divisors x = [(a, x/a) | a <- [2..(sqrt x)], x `mod` a == 0]
我想要获得的是x
的除数:包含(n, k)
的元组列表,例如n * k = x
示例:
> divisors x
[(1,10), (2, 5)]
为什么上面的代码不起作用?
它给了我错误:
*Main> divisors 10
<interactive>:1:0:
Ambiguous type variable `t' in the constraints:
`Floating t'
arising from a use of `divisors' at <interactive>:1:0-10
`Integral t'
arising from a use of `divisors' at <interactive>:1:0-10
Probable fix: add a type signature that fixes these type variable(s)
我尝试手动设置功能的签名但没有成功......
答案 0 :(得分:4)
问题是sqrt
返回Floating a
,你真的只想在找到除数时使用整数。您可以使用Floating a
,Integral a
或ceiling
将floor
变为round
。我将使用ceiling
,因为我不确定使用floor
或average
是否会跳过除数。
sqrt函数也只接受浮点数,因此您必须先将整数转换为浮点数(然后才能将其赋予它)(可以使用fromIntegral
完成)。
此外,您使用/
,它也适用于浮动数字。使用div
更好,因为它适用于整数(必要时舍入)。
divisors x = [(a, x `div` a) | a <- [2..(ceiling $ sqrt $ fromIntegral x)], x `mod` a == 0]
有了这个,divisors 10
会给[(2,5)]
(你的代码会阻止(1,10)
案例的发生 - 我猜这是故意的)。不幸的是,您会收到重复项,例如divisors 12
会返回[(2,6),(3,4),(4,3)]
,但如果这是一个问题,这不应该太难修复。
答案 1 :(得分:4)
如果您要求输入类型,可以看到问题:
divisors :: (Integral t, Floating t) => t -> [(t, t)]
然后检查Integral
和Floating
:
Prelude> :info Floating
class Fractional a => Floating a where
instance Floating Float -- Defined in GHC.Float
instance Floating Double -- Defined in GHC.Float
和
Prelude> :info Integral
class (Real a, Enum a) => Integral a where
instance Integral Integer -- Defined in GHC.Real
instance Integral Int -- Defined in GHC.Real
所以,它既不是Int,Integer,Float也不是Double。你遇到了麻烦......
值得庆幸的是,我们可以在不同类型之间进行转换,因此虽然sqrt
需要浮动,而mod
需要积分(顺便说一下,rem
更快),我们也可以,例如,取消浮点除法:
divisors :: Integer -> [(Integer, Integer)]
divisors x = [(a, x `div` a) | a <- [2..ceiling (sqrt (fromIntegral x))], x `rem` a == 0]
> divisors 100
[(2,0),(4,0),(5,0),(10,0)]
但是,您需要仔细考虑将整数类型转换为浮点数时的真正意义,通过sqrt
...
答案 2 :(得分:3)
在Haskell中,整数除法和小数除法是不同的操作,并且具有不同的名称。斜杠运算符/
用于小数除法。整数除法由div
或quot
完成(当涉及负数时,两者之间的差异与行为有关)。
尝试用
替换x/a
x `quot` a
代替。
编译器错误正好告诉您:您有时将某种类型视为整数(使用mod
),有时将其视为小数(使用/
),并且它不确定如何选择一种类似于这两者的类型。
但是,一旦排序,您将遇到与sqrt
类似的问题。同样,您需要确定您的类型是整数还是(在这种情况下)浮点。为了找到可能的除数,它应该足以达到小于浮点的最大整数,因此请考虑使用floor (sqrt (fromIntegral x)))
。 fromIntegral
将x
(必须具有整数类型)转换为其他类型 - 在这种情况下,它将默认为Double
。 floor
然后将Double
结果转换回整数类型。
答案 3 :(得分:1)
不是采用平方根来绑定搜索,而是允许理解范围超出无限列表,并且当余数大于除数时使用takeWhile
来停止搜索:
divisors x = takeWhile (uncurry (<=)) [(a, x `div` a) | a <- [1..], x `mod` a == 0]
> divisors 100
[(1,100),(2,50),(4,25),(5,20),(10,10)]
注意:您的原始示例将(1,10)
显示为divisors
的{{1}}之一,因此我从10
而不是1
开始理解。< / p>
嗯,这会搜索超出平方根,直到它达到上面的下一个因素。
这个怎么样:
2