Вопрос

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)?

Это было полезно?

Решение

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.

Другие советы

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.

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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top