Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement "Ord" for algebraic data types in Haskell?

Tags:

haskell

Imagine you have a rating like

Rating = OneStar | TwoStars | ThreeStars | FourStars | FiveStars

What is the best way to instanciate/implement "Ord" for such an algebraic data type in Haskell?

like image 490
LennyStackOverflow Avatar asked Aug 16 '11 14:08

LennyStackOverflow


People also ask

What is algebraic data type in Haskell?

This is a type where we specify the shape of each of the elements. Wikipedia has a thorough discussion. "Algebraic" refers to the property that an Algebraic Data Type is created by "algebraic" operations. The "algebra" here is "sums" and "products": "sum" is alternation ( A | B , meaning A or B but not both)

How do you declare types in Haskell?

Haskell has three basic ways to declare a new type: The data declaration, which defines new data types. The type declaration for type synonyms, that is, alternative names for existing types. The newtype declaration, which defines new data types equivalent to existing ones.

How do types work in Haskell?

In Haskell, every statement is considered as a mathematical expression and the category of this expression is called as a Type. You can say that "Type" is the data type of the expression used at compile time. To learn more about the Type, we will use the ":t" command.


3 Answers

The best way would be to just add deriving (Eq, Ord) to the type's definition.

Since you listed your constructors in ascending order, the derived Ord instance will give you exactly the order you want.

However, if changing the order in the definition is not an option for some reason you can still derive Eq, since for that the order does not matter. Given an instance of Eq, we can manually write an instance for Ord. The most succinct way to define compare would probably be to spell out all the combinations for which compare should return LT and then simply use compare x y | x == y = Eq; compare _ _ = GT for the remaining combinations.

like image 162
sepp2k Avatar answered Oct 03 '22 03:10

sepp2k


As has been mention, you can derive Eq and Ord. Or you could derive Enum and then do

instance Eq Rating where
    x == y = fromEnum x == fromEnum y

Or just spell it all out

instance Eq Rating where
    OneStar == OneStar = True
    TwoStar == TwoStar = True
...
    _ == _ = False
like image 37
augustss Avatar answered Oct 03 '22 03:10

augustss


For anyone wondering, here is the complete, explicit, boilerplate implementation:

Using roman numerals.
Using case for ease of reading.

data RN = I | II | III | IV | V

instance Eq RN where
    I == I     = True
    I == _     = False
    II == II   = True
    II == _    = False
    III == III = True
    III == _   = False
    IV == IV   = True
    IV == _    = False
    V == V     = True
    V == _     = False

instance Ord RN where
    compare I x = case x of
        I   -> EQ
        _   -> LT
    compare II x = case x of
        I   -> GT
        II  -> EQ
        _   -> LT
    compare III x = case x of
        III -> EQ
        _   -> GT
        _   -> LT
    compare IV x = case x of
        V   -> LT
        IV  -> EQ
        _   -> GT
    compare V x = case x of
        V   -> EQ
        _   -> GT
like image 24
schuelermine Avatar answered Oct 03 '22 04:10

schuelermine