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
?
Using infer in TypeScript It does that by first checking whether your type argument ( T ) is a function, and in the process of checking, the return type is made into a variable, infer R , and returned if the check succeeds: type ReturnType<T> = T extends (... args: any[]) => infer R ?
Infer is there to tell compiler that a new type variable R is declared within the scope of UnpackArrayType. type t2 = UnpackArrayType<string>; //t2 is string. For t2 , the condition in UnpackArrayType is false as the string type does not match with (infer R)[] , so it is returned as string.
Type inference is the ability to automatically deduce, either partially or fully, the type of an expression at compile time. The compiler is often able to infer the type of a variable or the type signature of a function, without explicit type annotations having been given.
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 for runcountacc
, 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 an Eq
instance to satisfy the constraints on runcountacc
, and there's no way to figure out which Eq
instance to use. It's genuinely ambiguous.
There are plenty of ways you can rewrite this code to sort out this ambiguity.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With