Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I declare the inferred type?

Tags:

types

haskell

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?

like image 861
Adam Lynch Avatar asked Nov 24 '11 15:11

Adam Lynch


People also ask

How do you type infer TypeScript?

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 ?

What is infer in JavaScript?

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.

What is inferred type?

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.


1 Answers

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.

like image 99
pigworker Avatar answered Oct 10 '22 19:10

pigworker