GHC (Glasgow Haskell Compiler) is the current de-facto standard and the most used Haskell compiler. It is also reputed with having hard to read error messages. This post will aim to explain a few of its errors. It will also (mostly implicitly) aim to show you how explicit type signatures can really help you write better code.
Error #1: Occurs check: cannot construct the infinite type: a ~ [a]
I'm sure many people have seen this one. This error can be created using ghci:
GHCi, version 8.8.3: https://www.haskell.org/ghc/ :? for help
Prelude> :{
Prelude| foo :: a -> [a]
Prelude| foo x = x
Prelude| :}
<interactive>:3:9: error:
* Occurs check: cannot construct the infinite type: a ~ [a]
* In the expression: x
In an equation for `foo': foo x = x
* Relevant bindings include
x :: a (bound at <interactive>:3:5)
foo :: a -> [a] (bound at <interactive>:3:1)
Prelude>
This is a very simple piece of code and is not practical or elegant, but it will suffice for this example. Before we go into the details of the error, it is helpful to notice a few things:
xhas the typeafoois expected to return the type[a]- The action of
fooreturningxis invalid becausexis of typeawhilefooexpects it to be of type[a]
After the last point, its clear an error should be raised because type a cannot be type [a]. But why? Can't a be specialized to type [a]? No, it can't for various reasons. If a is specialized to type [a], then the a in type [a], can be expanded to [[a]] which can be infinitely expanded, hence the error message. This is a great example of how explicit type signatures can increase safety (and possibly drive you nuts).
Error #2: 'a' is a rigid type variable
Another very common error. This error can also be created using ghci:
GHCi, version 8.8.3: https://www.haskell.org/ghc/ :? for help
Prelude> :{
Prelude| foo :: a -> a
Prelude| foo x = x ++ x
Prelude| :}
<interactive>:3:9: error:
* Couldn't match expected type `[a0]' with actual type `a'
`a' is a rigid type variable bound by
the type signature for:
foo :: forall a. a -> a
at <interactive>:2:1-13
* In the first argument of `(++)', namely `x'
In the expression: x ++ x
In an equation for `foo': foo x = x ++ x
* Relevant bindings include
x :: a (bound at <interactive>:3:5)
foo :: a -> a (bound at <interactive>:3:1)
Prelude>
Again a very simple piece of code. It should be obvious why this doesn't type check (++ takes two lists as arguments which were not supplied), but the "rigid variable" part can be confusing. As before, let's take a closer look at the code:
xis of typea++expects two lists of typea- The action of using
++onxtwice is invalid becausexis of typeawhile it is expected to be of type[a]
The last point makes it clear that an error should be raised because the type a cannot be type [a]. But why? Why can't a be specialized to type [a]? Imagine if instead of passing a list of something you passed an Int. How would ++ be used on the Int (remember that ++ expects to list of type a)? It can't, so it raises the error that you see.
Another question a few people might have is "What does rigid mean? Isn't a supposed to be polymorphic (can be any type) which is the opposite of rigid?". You're right that it is the opposite of rigid, but that is on the caller's side, not the definition side.
This code could be easily fixed by changing the function's type signature:
GHCi, version 8.8.3: https://www.haskell.org/ghc/ :? for help
Prelude> :{
Prelude| foo :: [a] -> [a]
Prelude| foo xs = xs ++ xs
Prelude| :}
Prelude>
Prelude> foo [1 .. 5]
[1,2,3,4,5,1,2,3,4,5]
Prelude>
Error #3: No instance for (Foo a) arising from a use of 'foo'
This is arguably the most made beginner mistake. As always this error can be created using ghci:
GHCi, version 8.8.3: https://www.haskell.org/ghc/ :? for help
Prelude> :{
Prelude| foo :: a -> a -> a
Prelude| foo x y = x + y
Prelude| :}
<interactive>:3:11: error:
* No instance for (Num a) arising from a use of `+'
Possible fix:
add (Num a) to the context of
the type signature for:
foo :: forall a. a -> a -> a
* In the expression: x + y
In an equation for `foo': foo x y = x + y
Prelude>
Let's notice a few things before digging into the error:
xandyare of typea+has the type signatureNum a => a -> a -> a, which means that the typeahas to have aNuminstance. You can read up on instances (and a few other helpful things) here
So why do we get an error? Because x and y are not constrained by Num. So the error is justified because you can't expect to pass in two strings and get them added up with +!
This code could easily be fixed in many different ways:
GHCi, version 8.8.3: https://www.haskell.org/ghc/ :? for help
Prelude> :{
Prelude| foo :: Num a => a -> a -> a
Prelude| foo x y = x + y
Prelude| :}
Prelude>
Prelude> :{
Prelude| foo' :: Int -> Int -> Int
Prelude| foo' x y = x + y
Prelude| :}
Prelude>
Prelude> foo 10 5
15
Prelude> foo' 10 5
15
Prelude>
Notice the difference in the type signatures. As you can see, the last method explicitly states that it will only take in Ints as arguments, which means it cannot accept Floats, Doubles, etc.; The first method uses type constraints and is more flexible (but not necessarily better) because it can take in Ints, Integers1, Floats, Doubles, and Words, and any other instance of Num.
Error #4: Could not deduce (Foo a) arising from a use of 'foo'
As always this error can be created using ghci:
GHCi, version 8.8.3: https://www.haskell.org/ghc/ :? for help
Prelude> :{
Prelude| foo :: Num a => String -> a
Prelude| foo x = read x
Prelude| :}
<interactive>:3:9: error:
* Could not deduce (Read a) arising from a use of `read'
from the context: Num a
bound by the type signature for:
foo :: forall a. Num a => String -> a
at <interactive>:2:1-27
Possible fix:
add (Read a) to the context of
the type signature for:
foo :: forall a. Num a => String -> a
* In the expression: read x
In an equation for `foo': foo x = read x
Prelude>
If you think about this for a while the reason for this error is self-evident. It is very similar to the previous error. read doesn't know what type to read the string as. It could be read as an Int, Float, Word, etc.
This can easily be fixed by adding en explicit type signature like so:
GHCi, version 8.8.3: https://www.haskell.org/ghc/ :? for help
Prelude> :{
Prelude| foo :: String -> Int
Prelude| foo x = read x
Prelude| :}
Prelude>
Prelude> foo "123"
123
Prelude>
Error #5: Ambiguous type variable `a0' arising from a use of 'foo'
Here is the large, scary error made using ghci:
GHCi, version 8.8.3: https://www.haskell.org/ghc/ :? for help
Prelude> :{
Prelude| class FooBar a where
Prelude| foobar :: a -> a
Prelude|
Prelude| instance FooBar Int where
Prelude| foobar 0 = 0
Prelude| foobar x = x + x
Prelude| :}
Prelude>
Prelude> foobar 10
<interactive>:10:1: error:
* Ambiguous type variable `a0' arising from a use of `print'
prevents the constraint `(Show a0)' from being solved.
Probable fix: use a type annotation to specify what `a0' should be.
These potential instances exist:
instance Show Ordering -- Defined in `GHC.Show'
instance Show Integer -- Defined in `GHC.Show'
instance Show a => Show (Maybe a) -- Defined in `GHC.Show'
...plus 22 others
...plus 12 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
* In a stmt of an interactive GHCi command: print it
Prelude>
This uses type classes, so if you don't know what they are take a look here. Before going into detail about the error, let's observe a few things about the code:
foobartakes something of typeaand returns something of typeaInthas an instance ofFooBar(which means you can use the functionfoobaron anInt)
So what is the problem with calling foobar 10? The problem is... 10 isn't an Int. Wait, what? 10 is not an Int? Yep. If you type :t 10 into ghci (:t gets the type of whatever you pass in), you'll get Num p => p as its type. That means it's not an exactly an Int, just an instance of Num (I hope this doesn't sound too confusing), which means depending on the context, it can be any of its instances (Int, Integer, Float, etc). The problem here is it doesn't know what instance to be.
This could be fixed by telling it what to be by adding an explicit type annotation, just as the error message suggested (notice the call to foobar):
GHCi, version 8.8.3: https://www.haskell.org/ghc/ :? for help
Prelude> :{
Prelude| class FooBar a where
Prelude| foobar :: a -> a
Prelude|
Prelude| instance FooBar Int where
Prelude| foobar 0 = 0
Prelude| foobar x = x + x
Prelude| :}
Prelude>
Prelude> foobar 10 :: Int
20
Prelude>
Conclusion
I hope you learned a thing or two about GHCs error messages and how to handle them. Moral of this post: Explicit type signatures = More errors caught = Better code = Happy coding!