3
votes

I just couldn't find out how can I implement a special ord for my datatypes in haskell. I read on the forum, that it should look somewhat like this:

import Data.Set

data Cord = Cord { x :: Int
                 , y :: Int} deriving (Eq,Ord)

instance Eq Cord where
    (Cord a b) == (Cord a b) = (a==c and b==d) 

instance Ord Cord where
    compare (Cord a b) (Cord c d) = if a==c then compare (b d) else compare(a c)

I want to create a simple type with 2 integers, and one is larger then the other if his first number is larger then the other ones first number, or the second ones if the firsts are equal. I know that this comparison can be done by creating lists of 2 integers, however i wan't to some lot more complex data types and can't find anywhere a guide how to define an ord with if-s and recursions.

Thank you for your anwser!

3

3 Answers

3
votes

I think your real issue is that you've used deriving (Eq, Ord), which implies that you already have a derived typeclass instance for Ord. If you remove that and use your comparison, it seems fine:

data Cord = Cord { x :: Int, y :: Int }
  deriving (Eq, Show)

instance Ord Cord where
  compare (Cord a b) (Cord c d) = if a == c then compare b d else compare a c   

In GHCI:

*Main> compare (Cord 4 2) (Cord 9 6)
LT
*Main> compare (Cord 3 2) (Cord 3 0)
GT
*Main> compare (Cord 2 2) (Cord 2 2)
EQ
2
votes

One helpful thing for Ord is its instance of Monoid so you can combine your case like this

instance Ord Coordinate where
    compare (Coord x1 x2) (Coord y1 y2) = (compare x1 y1) <> (compare x2 y2)

you might need to import Data.Monoid in order to have (<>) at your hands. This "trick" enables you to abstract the traversing/if-then-elsing/recursing over your data structure from the actual operation of comparing the sub results.

If you tell me what your datatype is - I could (maybe) give you more concrete hints how to do this.


Edit

A bit more explanation on the Monoid thing:

A Monoid is a datastructure that has an (associative) operation <> that allows you to combine two datastructures and a neutral element mempty that has the following property:

 x <> mempty = x
 mempty <> x = x

the easiest example you can think of is your data structure being the good old list [a] then where the combination operator is just concatenation of lists (<>) = (++) and the neutral element is the empty list mempty = [].

For the Ord the combination is slightly more complicated - compare yields something of type Ordering which is just one of EQ|LT|GT so we have to define two things for it to be a Monoid

 mempty = EQ
 LT <> _ = LT
 GT <> _ = GT
 EQ <> x = x

Monoids are a quite convenient way of abstracting things so they are a neat trick to have up your sleeve.

0
votes

You can define an instance of a typeclass with any functions you like (that have the correct signature).

As an example:

newtype LexInt = LexInt [Int] -- ints in reverse digit order
instance Eq LexInt where
    (==) (LexInt (l:ls)) (LexInt (r:rs)) = (l == r) && ((LexInt ls) == (LexInt rs))
    (==) (LexInt []) (LexInt []) = True
    (==) _ _ = False