content: -- Exercise set 6: defining classes and instances
  
  module Set6 where
  
  import Mooc.Todo
  import Data.Char (toLower)
  
  ------------------------------------------------------------------------------
  -- Ex 1: define an Eq instance for the type Country below. You'll need
  -- to use pattern matching.
  
  data Country = Finland | Switzerland | Norway
    deriving Show
  
  instance Eq Country where
    (==) = todo
  
  ------------------------------------------------------------------------------
  -- Ex 2: implement an Ord instance for Country so that
  --   Finland <= Norway <= Switzerland
  --
  -- Remember minimal complete definitions!
  
  instance Ord Country where
    compare = todo -- implement me?
    (<=) = todo -- and me?
    min = todo -- and me?
    max = todo -- and me?
  
  ------------------------------------------------------------------------------
  -- Ex 3: Implement an Eq instance for the type Name which contains a String.
  -- The Eq instance should ignore capitalization.
  --
  -- Hint: use the function Data.Char.toLower that has been imported for you.
  --
  -- Examples:
  --   Name "Pekka" == Name "pekka"   ==> True
  --   Name "Pekka!" == Name "pekka"  ==> False
  
  data Name = Name String
    deriving Show
  
  instance Eq Name where
    (==) = todo
  
  ------------------------------------------------------------------------------
  -- Ex 4: here is a list type parameterized over the type it contains.
  -- Implement an instance "Eq (List a)" that compares the lists element
  -- by element.
  --
  -- Note how the instance needs an Eq a constraint. What happens if you
  -- remove it?
  
  data List a = Empty | LNode a (List a)
    deriving Show
  
  instance Eq a => Eq (List a) where
    (==) = todo
  
  ------------------------------------------------------------------------------
  -- Ex 5: below you'll find two datatypes, Egg and Milk. Implement a
  -- type class Price, containing a function price. The price function
  -- should return the price of an item.
  --
  -- The prices should be as follows:
  -- * chicken eggs cost 20
  -- * chocolate eggs cost 30
  -- * milk costs 15 per liter
  --
  -- Example:
  --   price ChickenEgg  ==>  20
  
  data Egg = ChickenEgg | ChocolateEgg
    deriving Show
  data Milk = Milk Int -- amount in litres
    deriving Show
  
  
  ------------------------------------------------------------------------------
  -- Ex 6: define the necessary instance hierarchy in order to be able
  -- to compute these:
  --
  -- price (Just ChickenEgg) ==> 20
  -- price [Milk 1, Milk 2]  ==> 45
  -- price [Just ChocolateEgg, Nothing, Just ChickenEgg]  ==> 50
  -- price [Nothing, Nothing, Just (Milk 1), Just (Milk 2)]  ==> 45
  
  
  ------------------------------------------------------------------------------
  -- Ex 7: below you'll find the datatype Number, which is either an
  -- Integer, or a special value Infinite.
  --
  -- Implement an Ord instance so that finite Numbers compare normally,
  -- and Infinite is greater than any other value.
  
  data Number = Finite Integer | Infinite
    deriving (Show,Eq)
  
  
  ------------------------------------------------------------------------------
  -- Ex 8: rational numbers have a numerator and a denominator that are
  -- integers, usually separated by a horizontal bar or a slash:
  --
  --      numerator
  --    -------------  ==  numerator / denominator
  --     denominator
  --
  -- You may remember from school that two rationals a/b and c/d are
  -- equal when a*d == b*c. Implement the Eq instance for rationals
  -- using this definition.
  --
  -- You may assume in all exercises that the denominator is always
  -- positive and nonzero.
  --
  -- Examples:
  --   RationalNumber 4 5 == RationalNumber 4 5    ==> True
  --   RationalNumber 12 15 == RationalNumber 4 5  ==> True
  --   RationalNumber 13 15 == RationalNumber 4 5  ==> False
  
  data RationalNumber = RationalNumber Integer Integer
    deriving Show
  
  instance Eq RationalNumber where
    p == q = todo
  
  ------------------------------------------------------------------------------
  -- Ex 9: implement the function simplify, which simplifies a rational
  -- number by removing common factors of the numerator and denominator.
  -- In other words,
  --
  --     ca         a
  --    ----  ==>  ---
  --     cb         b
  --
  -- As a concrete example,
  --
  --     12        3 * 4         4
  --    ----  ==  -------  ==>  ---.
  --     15        3 * 5         5
  --
  -- Hint: Remember the function gcd?
  
  simplify :: RationalNumber -> RationalNumber
  simplify p = todo
  
  ------------------------------------------------------------------------------
  -- Ex 10: implement the typeclass Num for RationalNumber. The results
  -- of addition and multiplication must be simplified.
  --
  -- Reminders:
  --   * negate x is 0-x
  --   * abs is absolute value
  --   * signum is -1, +1 or 0 depending on the sign of the input
  --
  -- Examples:
  --   RationalNumber 1 3 + RationalNumber 1 6 ==> RationalNumber 1 2
  --   RationalNumber 1 3 * RationalNumber 3 1 ==> RationalNumber 1 1
  --   negate (RationalNumber 2 3)             ==> RationalNumber (-2) 3
  --   fromInteger 17 :: RationalNumber        ==> RationalNumber 17 1
  --   abs (RationalNumber (-3) 2)             ==> RationalNumber 3 2
  --   signum (RationalNumber (-3) 2)          ==> RationalNumber (-1) 1
  --   signum (RationalNumber 0 2)             ==> RationalNumber 0 1
  
  instance Num RationalNumber where
    p + q = todo
    p * q = todo
    abs q = todo
    signum q = todo
    fromInteger x = todo
    negate q = todo
  
  ------------------------------------------------------------------------------
  -- Ex 11: a class for adding things. Define a class Addable with a
  -- constant `zero` and a function `add`. Define instances of Addable
  -- for Integers and lists. Numbers are added with the usual addition,
  -- while lists are added by catenating them. Pick a value for `zero`
  -- such that: `add zero x == x`
  --
  -- Examples:
  --   add 1 2                ==>  3
  --   add 1 zero             ==>  1
  --   add [1,2] [3,4]        ==>  [1,2,3,4]
  --   add zero [True,False]  ==>  [True,False]
  
  
  ------------------------------------------------------------------------------
  -- Ex 12: cycling. Implement a type class Cycle that contains a
  -- function `step` that cycles through the values of the type.
  -- Implement instances for Color and Suit that work like this:
  --
  --   step Red ==> Green
  --   step Green ==> Blue
  --   step Blue ==> Red
  --
  -- The suit instance should cycle suits in the order Club, Spade,
  -- Diamond, Heart, Club.
  --
  -- Also add a function `stepMany` to the class and give it a default
  -- implementation using `step`. The function `stepMany` should take
  -- multiple (determined by an Int argument) steps like this:
  --
  --   stepMany 2 Club ==> Diamond
  --   stepMany 3 Diamond ==> Spade
  --
  -- The tests will test the Cycle class and your default implementation
  -- of stepMany by adding an instance like this:
  --
  --    instance Cycle Int where
  --      step = succ
  
  data Color = Red | Green | Blue
    deriving (Show, Eq)
  data Suit = Club | Spade | Diamond | Heart
    deriving (Show, Eq)
  
  