Вопрос

I wrote a little haskell program that just counts how many ones there are in a number (Int). When I try to execute it haskell complains about ambigous variable constraints. I know that it comes from the use of floor. I also read some of the answers on stackoverflow. But I didn't really find a way around that. Here's my code:

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)

Any advice?

Это было полезно?

Решение

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)

In the first line, you compare n - 10*n_new to the fractional literal 0.1, so the type of n and n_new must be a member of the Fractional class.

In the where clause, you bind n_new = floor (n/10), so the type of n_new must be a member of the Integral class.

Since no standard type is a member of both classes (for good reasons), the compiler can't resolve the constraint

(Fractional a, Integral a) => a

when the function is called.

If you give type signatures to your functions, the compiler can often generate more helpful error messages.

The simplest fix for your problem is to change the binding of n_new to

n_new = fromIntegral (floor $ n/10)

Considering that in the comments you said that the 0.1 was a mistake and you should have used 1 instead, you probably want to use Integral types only and the closest transcription of your code would be

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

but it might be clearer to replace the condition n - 10*n_new == 1 with n `mod` 10 == 1.

However, that would require two divisions per step, which probably is less efficient. Using divMod should give you the quotient and remainder of the division with only one division instruction,

count_ones' m n = case n `divMod` 10 of
                    (q,1) -> count_ones' (m+1) q
                    (q,_) -> count_ones' m q

and if you can guarantee that you will only call the function with non-negative n, use quot and rem resp. quotRem instead of div and mod resp. divMod. The former functions use the results of the machine division instruction directly, while the latter need some post-processing to ensure that the result of mod is non-negative, so quot and friends are more efficient than div and company.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top