模糊类型变量

时间:2012-09-10 14:45:59

标签: haskell type-constraints

我写了一个小的haskell程序,只计算一个数字(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)

有什么建议吗?

1 个答案:

答案 0 :(得分: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的成员} class。

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的函数,请使用quotrem resp。 quotRem代替divmoddivMod。前面的函数直接使用机器划分指令的结果,而后者需要一些后处理来确保mod的结果是非负的,所以quot和朋友比{更有效率} {1}}和公司。