Rumca
Rumca

Reputation: 1829

Haskell function argument type inference with typeclasses

I'm trying to understand haskell error messages, as they are confusing for novice programmer. The simplest example I could find is this:

Prelude> 1 + True
<interactive>:2:3:
No instance for (Num Bool)
  arising from a use of `+'
Possible fix: add an instance declaration for (Num Bool)
In the expression: 1 + True
In an equation for `it': it = 1 + True

Why does compiler look for (Num Bool) regardless of parameter order? Why does it work after I define the following?

instance Num Bool where (+) a b = True;
[...]
Prelude> 1 + True
True

How can I make sure (+) can be applied to (Num Bool) only when second argument is also (Num Bool)?

Upvotes: 2

Views: 231

Answers (3)

Tikhon Jelvis
Tikhon Jelvis

Reputation: 68152

You get this error message because both 1 and + are polymorphic--they can both work for different types!

Take a look:

Prelude> :t 1
1 :: Num a => a
Prelude> :t (+)
(+) :: Num a => a -> a -> a

So both 1 and + are meaningful for any type in the Num class. So when you write 1 + Bool, the 1 could actually be a Bool, if Bool had a Num instance. In fact, you can do that yourself:

instance Num Bool where
  fromInteger x = x /= 0
  (+) = (&&)
  ...

Once you do this, 1 + True will actually work. You will also be able to use numeric literals as bools:

*Main> 1 :: Bool
True
*Main> 1 + True
True

This also explains why you get the same error regardless of the order of arguments: the only actual problem in your code is the True--if that worked, everything else would too.

Upvotes: 4

chamini2
chamini2

Reputation: 2918

The error message is saying that the data Bool is not an instance of the class Num, if you run in ghci the following command

Prelude> :info Num
class Num a where
  (+) :: a -> a -> a
  (*) :: a -> a -> a
  (-) :: a -> a -> a
  negate :: a -> a
  abs :: a -> a
  signum :: a -> a
  fromInteger :: Integer -> a
    -- Defined in `GHC.Num'
instance Num Integer -- Defined in `GHC.Num'
instance Num Int -- Defined in `GHC.Num'
instance Num Float -- Defined in `GHC.Float'
instance Num Double -- Defined in `GHC.Float'

You can see that a Num is a thing that can be added (+), multiplied (*), substracted (-), and so on.

As a Bool can't behave like this, it doesn't have an instance of Num. That explains the line in the error No instance for (Num Bool) since (+) can only be used on instances of Num

What you are doing in instance Num Bool where (+) a b = True is saying that now a Bool behaves also like a Num, so you have to specify how a Bool can be added (+), multiplied (*), etc.

I hope I explained in a simple enough way.

Upvotes: 0

Ingo
Ingo

Reputation: 36329

It is the contract of Num that any numeric integer literal can be converted to the desired type.

With your declaration, Haskell tries in reality:

fromIntegral 1 + True

which probably calls your boolean (+) with the first argument undefined. But it doesn't matter, since you never evaluate it.

Try writing it thus:

(+) a b = if a then True else False

and you'll probably see an error.

Upvotes: 1

Related Questions