Creating Instance of Eq for custom data type in Haskell
Asked Answered
G

1

7

I have made some custom Data types for number representation in Haskell, now I want to implement Eq instances for it, but I am somehow stuck. So I have already made:

data Digit = Zero | One | Two
type Digits = [Digit]
data Sign = Pos | Neg -- Pos fuer Positive, Neg fuer Negative
newtype Numeral = Num (Sign,Digits)

instance Eq Sign where
(==) Pos Pos = True
(==) Neg Neg = True
(==) _ _ = False

instance Eq Digit where
(==) Zero Zero = True
(==) One One = True
(==) Two Two = True
(==) _ _ = False

Now I want to check out the Sign in my custom type Numeral so I tried this:

instance (Eq Sign) => Eq (Numeral) where
(==) Num(x,_)== Num(y,_) = x==y

But I get this error: Parse error in pattern : (==)

Granger answered 19/11, 2016 at 16:7 Comment(6)
Either (==) (Num (x,_)) (Num (y,_)) = x==y or Num (x,_) == Num (y,_) = x==y.Monney
Also why do you use a newtype for Numeral. Why not data Numeral = Num Sign Digits?Monney
When I type the first case you wrote it says Ambiguous occurrence ‘==’ but before that it says it's multiple times declared ( I guess in previous instances), and the second case doesn't work as wellGranger
because I'm trying to solve problem from the bookGranger
You have to indent the definitions for the functions of the instances. In Haskell whitespace is significant.Monney
Furthermore it should just be instance Eq Numeral where. You don't have to say that this instance is only valid with a Eq instance for Sign, because Sign is a concrete type and therefore either always or never has an Eq instance. In this case always, because you defined one.Monney
M
6

Mostly putting what I've already written in the comments in a more fleshed out form:

There are a few problems with your code:

  1. You have to indent the code under the instance declarations. That way you tell the compiler what code belongs to the instance declaration.
  2. In the following line you are asking for a type class constraint on a concrete type (Eq Sign =>). This is not possible in standard Haskell and even if you were to follow the compiler instructions and enable the FlexibleInstances language extension it wouldn't make sense.

    instance (Eq Sign) => Eq (Numeral) where
    

    Type class constraints are only used for type variables. For example:

    double :: Num a => a -> a
    double x = x + x
    

    Here we say, that the function double only works for all types that implement Num. double :: Num Int => Int -> Int on the other hand is redundant, because we already know, that Int has a Num instance. The same for Eq Sign.

    For instances such constraints only make sense, if the type you are writing an instance for contains another polymorphic type. Fox example instance Ord a => Ord [a]. Here we would use the Ord instance of the elements of the list to lexiographically order lists.

  3. You can define (==) either in infix or prefix form, but not both. So either (==) (Num (x,_)) (Num (y,_)) = x == y or Num (x,_) == Num (y,_) = x == y.

  4. Newtyping tuples to create a product type is rather strange. Newtypes are usually used if you want to use the functionality that is already present for the more complex underlying type. However here that is not the case, you just want a normal product of Digits and Sign.

  5. You are only comparing the Sign of the numbers. While technically a valid Eq instance, I think you also want to compare the digits of the number probably truncating leading zeros. In the code below I didn't truncate zeros though, to keep it simple.

data Digit = Zero | One | Two
type Digits = [Digit]
data Sign = Pos | Neg
data Numeral = Num Sign Digits

instance Eq Sign where
  (==) Pos Pos = True
  (==) Neg Neg = True
  (==) _ _ = False

instance Eq Digit where
  (==) Zero Zero = True
  (==) One One = True
  (==) Two Two = True
  (==) _ _ = False

instance Eq Numeral where
  Num s1 x1 == Num s2 x2 = s1 == s2 && x1 == x2
Monney answered 19/11, 2016 at 16:50 Comment(2)
Very well explained. I have seen somewhere in tutorials that, for example, Eq a => Eq customType where is used. I understood it as including instance for comparing Signs into current instance. I know I compared just Signs, I wanted to make another instance of Eq for Numeral to compare Digits. I think I have tried what you wrote at the beginning but didn't work. Now I tried it again and it said "ambiguous occurence ==". Anyway, well explained.Granger
@PegasusThorn Thank you. I added a short paragraph to the end of 2. about type constraints in instance declarations.Monney

© 2022 - 2024 — McMap. All rights reserved.