Making Sense of GHC Error Messages: Part 1

Haskell compiler errors can at first seem obtuse but, once you get to know them, are in fact very descriptive and helpful, sometimes much more so than in other build environments!

In this series I’m going to pick apart the most common error messages, that baffled me at first coming from a C++ background, and hopefully it will save you some of the time that I had to spend, digging through the Haskell standards docs to get the answers :o)

Let’s start with:

No Instance for (Integral Float)

… or, more generally:

No Instance for ([numeric typeclass A] [numeric instance B])

Here’s a small code snippet:

divIntTest :: Float -> Float -> Float

divIntTest x y = x / (floor y)

This will generate the following error when loading into GHCi v. 7.0.3.

No instance for (Integral Float)

arising from a use of `floor'

Possible fix: add an instance declaration for (Integral Float)

In the second argument of `(/)', namely `(floor y)'

In the expression: x / (floor y)

In an equation for `divIntTest': divIntTest x y = x / (floor y)

The first line of this error is perhaps the hardest to grok – what does Integral Float even mean? Let’s examine the hierarchy* of Haskell’s basic numeric typeclasses (diagram re-drawn from paragraph 6.3 of the Haskell 98 Standards Document):

We see that class Num — the most abstract number representation — has four possible instances: Int (32-bit integer, similar to int in C/C++), Integer (a whole number of unbounded size), Float (32-bit IEEE compliant floating-point) and Double (64-bit floating-point representation).

In other words, if you had a function whose signature was

myFunc :: Num a => a -> a

… then could pass it an Int, or an Integer, or a Float, or a Double, and the compiler would be happy.

But if we look at some of the more derived classes, such as RealFrac, we see that it only has two instances: Float and Double. So the signature

myFunc :: RealFrac a => a -> a

… would only accept a Float, or a Double as an argument.

With this in mind, let’s return to the GHC error we are trying to resolve:

No instance for (Integral Float)

arising from a use of `floor'

If we look at the type signature of floor (type :type floor in GHCi):

floor :: (RealFrac a, Integral b) => a -> b

… we see that it returns an instance of class Integral. But if we look at the type signature of the division operator (type :type (/) in GHCi):

(/) :: Fractional a => a -> a -> a

… we see it expects and instance of class Fractional. If we compare the available instances of Integral and Fractional:

… we see there is no instance compatible with both. So the compiler has no way of converting from an Integral to a Fractional.

Returning to the error message one last time:

No instance for (Integral Float)

arising from a use of `floor'

In the second argument of `(/)', namely `(floor y)'

… we now see more clearly what it’s saying: the second argument of the division operator, (/) expects a Float; the return type of ‘floor’ is of class Integral, so the compiler searching for an instance of class Integral that matches a Float. Hence ‘No instance for (Integral Float)’: there is no instance of Float in the Integral class.

One possible fix would be to look for a way of converting the Integral output of ‘floor’ to an instance of Fractional. Happily, Prelude comes with the function

fromIntegral :: (Num b, Integral a) => a -> b

… that converts an Integral type to a Num type. Referring back to figure 1, we see that Num is a base class of — well, of every other numeric type! — so we can be confident that no matter what numeric type we need, fromIntegral will convert it for us. Let’s try:

divIntTest :: Float -> Float -> Float

divIntTest x y = x / (fromIntegral (floor y))

… this should compile and load without errors :o)

* “hierarchy” used here only in the loose sense that a typeclass on a lower rung, also accepts types on the higher rungs, to which it is connected, as input