2

我写了一个小程序,它只计算一个数字(Int)中有多少个。当我尝试执行它时,haskell 抱怨变量约束模棱两可。我知道它来自地板的使用。我还阅读了有关 stackoverflow 的一些答案。但我并没有真正找到解决方法。这是我的代码:

count_ones = count_ones' 0

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 = floor (n/10)

有什么建议吗?

4

1 回答 1

5
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,因此nand的类型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,使用quotremresp。quotRem而不是divmodresp。divMod. 前者函数直接使用机器除法指令的结果,而后者需要一些后处理来保证结果mod是非负的,所以quot和朋友比div和公司效率更高。

于 2012-09-10T14:52:27.143 回答