mip42
mip42

Reputation: 65

Haskell: "Non type-variable argument in the constraint: Eq Bit" and "No instance for (Eq Bit) arising drom a use of '=='"

data Bit = One 
         | Zero
         deriving Show

type Bits = [Bit]

bits2String :: Bits -> String
bits2String [] = ""
bits2String (x:xs) | x == One = "1" ++ bits2String xs
                   | x == Zero = "0" ++ bits2String xs

This Code causes following error message:

No instance for (Eq Bit) arising drom a use of '=='

For this error you can find a lot of solutions on SO. They always say you need to add Eq like that:

bits2String :: (Eq Bit) => Bits -> String
bits2String [] = ""
bits2String (x:xs) | x == One = "1" ++ bits2String xs
                   | x == Zero = "0" ++ bits2String xs

But this doesnt work for me and causes following error

Non type-variable argument in the constraint: Eq Bit
(Use FlexibleContexts to permit this)

{-# LANGUAGE FlexibleContexts #-} doesnt work either.

Upvotes: 1

Views: 181

Answers (2)

Robin Zigmond
Robin Zigmond

Reputation: 18249

The original error message is the key one:

No instance for (Eq Bit) arising drom a use of '=='

This arises because you are using the == operator, which is only available for instances of the Eq typeclass - and you haven't given such an instance.

That's easily fixed though. For one you can easily provide the instance manually:

instance Eq Bit where
    One == One = True
    Zero == Zero = True
    _ == _ = False

I wouldn't recommend that you do that though. You can ask Haskell to generate that exact instance for you by simply adding a deriving clause to the type definition. In fact you're already using one, so you can just add Eq to the list of instances you want to derive:

data Bit = One 
     | Zero
     deriving (Show, Eq) 

Adding this instance is a good idea in general, because you might well need to compare Bits for equality at some point, especially when working with lists of them - many list functions such as elem depend on Eq instances for their members.

But you can rewrite your bits2String function to not need an Eq instance at all, by pattern matching on the two data constructors:

bits2String :: Bits -> String
bits2String [] = ""
bits2String (One:xs) = "1" ++ bits2String xs
bits2String (Zero:xs) = "0" ++ bits2String xs

In fact, you've basically reimplemented the map function here, so what I would likely do is to define:

bitToChar :: Bit -> Char
bitToChar Zero = '0'
bitToChar One = '1'

(especially as it's the kind of general utility function that you may well want for other things)

and then

bits2String = map bitToChar 

None of those require an Eq instance - but it's likely a good idea to derive it anyway, for the reasons I mentioned.

Upvotes: 2

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476574

You make use of x == Zero, so of the (==) :: Eq a => a -> a -> Bool function, but you did not make Bit an instance of Eq. You can do so by adding it to the deriving clause, such that Haskell can automatically implement an instance of Eq for your Bit data type:

data Bit = One 
         | Zero
         deriving (Eq, Show)

By default two items are the same if the data constructor is the same, and the parameters (but here your data constructors have no parameters, so it will only check equality of the data constructors).

That being said, you do not need these to be an instance of Eq, you can use pattern matching instead. Indeed:

bits2String :: Bits -> String
bits2String = map f
    where f Zero = '0'
          f One = '1'

Here we make use of map :: (a -> b) -> [a] -> [b] to convert a list of items to another list by applying a function to each of the items in the original list. Since Bits is a list of Bits, and String is a list of Chars, we can thus map each Bit to a Char to obtain a String of '0's and '1's for the Zero and Ones respectively.

Upvotes: 2

Related Questions