Hick
Hick

Reputation: 36404

No instance for (Integral [t0]) error in Haskell code

I'm getting an error:

No instance for (Integral [t0]) when I run this haskell code.

boomBangs xs = [(a,b,c) |a<-[1..xs],b<-[1..xs],c<-[1..xs], xs <- xs `div` 2]

Where am I going wrong?

Upvotes: 1

Views: 258

Answers (2)

Jon Purdy
Jon Purdy

Reputation: 55039

What you said was:

Give me a tuple of a, b, and c:

[ (a, b, c)

For each a, b, and c in the list of values from 1 to xs1:

| a <- [1..xs1]
, b <- [1..xs1]
, c <- [1..xs1]

For each xs2 in the quotient of xs1 and 2.

, xs2 <- xs1 `div` 2
]

If you compile with warnings enabled (-Wall) or turn them on in GHCi (:set -Wall) then you’ll get a warning that the xs in xs <- ... shadows the xs in boomBangs xs = ..., and also that it’s unused. Obviously this kind of warning can be very helpful, as it points right to your problem.

Since xs1 is the input to your function, you end up with a type like this:

(Integral [t]) => [t] -> [([t], [t], [t])]

Which is to say that the function takes a list (xs1) that can act as a number ((`div` 2)) and gives you back a list of tuples of such lists. Even though you’re trying to divide a list by a number, GHC allows it and infers a more general type because you could have defined an Integral instance for lists. It only discovers that you haven’t when you actually try to use the function on a concrete type. Writing down type signatures can help keep the compiler grounded and give you better error messages.

I can only guess you meant for boomBangs to have a type like:

Integral t => [t] -> [(t, t, t)]

Or just:

[Int] -> [(Int, Int, Int)]

In which case maybe you were thinking of something like this:

[ (a, b, c)
| x <- xs
, a <- [1..x `div` 2]
, b <- [1..x `div` 2]
, c <- [1..x `div` 2]
]

Upvotes: 6

Tikhon Jelvis
Tikhon Jelvis

Reputation: 68152

The problem is that you're trying to divide a list. In particular, xs `div` 2 is the incorrect expression.

You can get this from the error message: it's complaining that [t0] does not behave like an integer (e.g. it isn't in the Integral class). [t0] is just a list of stuff--the t0, being in lowercase, is a type variable that represntes any type.

Since lists of stuff aren't numbers, we can't really know how to divide them.

You can see why you get this exact error message by looking at the type of div:

div :: Integral i => i -> i -> i

All this means is that given some type i in the Integral class, you can divide two of them together to get a third. Since lists of things are not part of the integral class, you can't divide them and so you get an error.

If div had a concrete type like div :: Int -> Int -> Int, you would get an error telling you that it can't match the expected type Int with the actual type [t0]. However, since the type actually contains a variable i, the error is a bit more complex: [t0] cannot be a valid type to use in place of i because it is not in the Integral class.

Upvotes: 6

Related Questions