I have the following:
runcount :: (Eq a, Num b) => [a] -> b
runcount = runcountacc 0
runcountacc :: (Eq a, Num b) => b -> [a] -> b
runcountacc n (_:[]) = runcountacc (n+1) []
runcountacc n (x:xs) = runcountacc (n+(if head xs==x then 0 else 1)) xs
runcountacc n _ = n
Which generates this error when I try to load it into Hugs:
:6 - Cannot justify constraints in explicitly typed binding
*** Expression : runcountacc
*** Type : (Eq a, Num b) => b -> [a] -> b
*** Given context : (Eq a, Num b)
*** Constraints : Eq c
And the following error when loaded into ghci:
:6:23: Ambiguous type variable `a0' in the constraint:
(Eq a0) arising from a use of `runcountacc'
Probable fix: add a type signature that fixes these type variable(s)
In the expression: runcountacc (n + 1) []
In an equation for `runcountacc':
runcountacc n ([x]) = runcountacc (n + 1) []
However when the type declaration of runcountacc is removed:
runcount :: (Eq a, Num b) => [a] -> b
runcount = runcountacc 0
runcountacc n (_:[]) = runcountacc (n+1) []
runcountacc n (x:xs) = runcountacc (n+(if head xs==x then 0 else 1)) xs
runcountacc n _ = n
The code loads fine and when ghci is asked what the type of runcountacc is, we get the following:
λ> :t runcountacc
runcountacc :: (Num a, Eq a1) => a -> [a1] -> a
Why can’t I declare the inferred type of runcountacc?
My guess is that when you leave out the type signature, Haskell assumes you’re not intending to use polymorphic recursion (for which type inference is not so effective). Correspondingly, when you make that recursive call to
runcountacc (n + 1) [], the list element type is taken to be the same as in the original function call. The usual Hindley-Milner process works fine, computing a uniform monomorphic type forruncountacc, then forming a type scheme by generalizing over the free type variables and unsolved constraints.However, as soon as you write a type signature, you allow for the possibility of polymorphic recursion, and when you call
runcountacc (n + 1) [], there is no reason to assume that the undetermined element type for[]should be anything in particular. However, this undetermined type still needs anEqinstance to satisfy the constraints onruncountacc, and there’s no way to figure out whichEqinstance to use. It’s genuinely ambiguous.There are plenty of ways you can rewrite this code to sort out this ambiguity.