2012-09-10 44 views
2

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

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) 

有什么建议吗?

+2

什么是确切的错误信息? (并且您是否尝试过自己给出类型签名?) – huon

回答

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,所以nn_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 == 1n `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,使用quotrem RESP。 quotRem而不是divmoddivMod。前者功能直接使用机器分割指令的结果,而后者则需要一些后处理来确保mod的结果是非负的,所以quot和朋友比div和公司更有效率。

+0

感谢您的快速回复。那是我需要的。另外我想提示我在上面的代码中做了一个小错误。 0.1必须是1. –

+0

我想知道。那么你更希望这个类型是一个'Integral'类型,并且你可能应该使用'div,mod,quot,rem'的组合,而不是转换为除法的'Fractional'类型。 –

+0

如果您有时间获得简短的建议代码。请随时发送给我。我会很感激! –