count_ones' m n | n-10*n_new == 0.1 = count_ones' (m+1) n_new
| otherwise = count_ones' m n_new
where n_new = floor (n/10)
在第一行中,您与n - 10*n_new
小数字面量进行比较0.1
,因此n
and的类型n_new
必须是Fractional
该类的成员。
在where
子句中,您 bind n_new = floor (n/10)
,因此类型 ofn_new
必须是Integral
类的成员。
由于没有标准类型是两个类的成员(有充分的理由),编译器无法解析约束
(Fractional a, Integral a) => a
当函数被调用时。
如果为函数提供类型签名,编译器通常会生成更有用的错误消息。
解决您的问题的最简单方法是将绑定更改n_new
为
n_new = fromIntegral (floor $ n/10)
考虑到您在评论中说这0.1
是一个错误并且您应该使用它1
,您可能只想使用Integral
类型,并且您的代码最接近的转录是
count_ones' :: Integral a => Int -> a -> Int
count_ones' m 0 = m
count_ones' m n
| n - 10*n_new == 1 = count_ones' (m+1) n_new
| otherwise = count_ones' m n_new
where
n_new = n `div` 10
但n - 10*n_new == 1
用. 替换条件可能更清楚n `mod` 10 == 1
。
但是,这将需要每步进行两次划分,这可能效率较低。使用divMod
应该只用一个除法指令给你除法的商和余数,
count_ones' m n = case n `divMod` 10 of
(q,1) -> count_ones' (m+1) q
(q,_) -> count_ones' m q
如果你能保证你只会用非负数调用函数n
,使用quot
和rem
resp。quotRem
而不是div
和mod
resp。divMod
. 前者函数直接使用机器除法指令的结果,而后者需要一些后处理来保证结果mod
是非负的,所以quot
和朋友比div
和公司效率更高。