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
和n_new
类型必须是Fractional
类的成员。
在where
子句中,您绑定了n_new = floor (n/10)
,因此n_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
。 divMod
。前者功能直接使用机器分割指令的结果,而后者则需要一些后处理来确保mod
的结果是非负的,所以quot
和朋友比div
和公司更有效率。
什么是确切的错误信息? (并且您是否尝试过自己给出类型签名?) – huon