Reputation: 349
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?
Upvotes: 2
Views: 134
Reputation: 183873
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.
Upvotes: 5