module Numeric.Order.Class 
  ( Order(..)
  , orderOrd
  ) where

import Data.Int
import Data.Word
import Data.Set
import Numeric.Natural

-- a partial order (a, <=)
class Order a where
  (<~) :: a -> a -> Bool
  a <~ b = maybe False (<= EQ) (order a b)

  (<) :: a -> a -> Bool
  a < b = order a b == Just LT

  (>~) :: a -> a -> Bool
  a >~ b = b <~ a

  (>) :: a -> a -> Bool
  a > b = order a b == Just GT

  (~~) :: a -> a -> Bool
  a ~~ b = order a b == Just EQ

  (/~) :: a -> a -> Bool
  a /~ b = order a b /= Just EQ

  order :: a -> a -> Maybe Ordering
  order a b 
    | a <~ b = Just $ if b <~ a 
               then EQ
               else LT
    | b <~ a = Just GT
    | otherwise = Nothing

  comparable :: a -> a -> Bool
  comparable a b = maybe False (const True) (order a b)


orderOrd :: Ord a => a -> a -> Maybe Ordering
orderOrd a b = Just (compare a b)

instance Order Bool where order = orderOrd 
instance Order Integer where order = orderOrd 
instance Order Int where order = orderOrd 
instance Order Int8 where order = orderOrd 
instance Order Int16 where order = orderOrd 
instance Order Int32 where order = orderOrd 
instance Order Int64 where order = orderOrd 
instance Order Natural where order = orderOrd 
instance Order Word where order = orderOrd
instance Order Word8 where order = orderOrd
instance Order Word16 where order = orderOrd
instance Order Word32 where order = orderOrd
instance Order Word64 where order = orderOrd
instance Ord a => Order (Set a) where
  (<~) = isSubsetOf

instance Order () where 
  order _ _ = Just EQ
  _ <~ _ = True
  comparable _ _ = True

instance (Order a, Order b) => Order (a, b) where 
  (a,b) <~ (i,j) = a <~ i && b <~ j

instance (Order a, Order b, Order c) => Order (a, b, c) where 
  (a,b,c) <~ (i,j,k) = a <~ i && b <~ j && c <~ k

instance (Order a, Order b, Order c, Order d) => Order (a, b, c, d) where 
  (a,b,c,d) <~ (i,j,k,l) = a <~ i && b <~ j && c <~ k && d <~ l

instance (Order a, Order b, Order c, Order d, Order e) => Order (a, b, c, d, e) where 
  (a,b,c,d,e) <~ (i,j,k,l,m) = a <~ i && b <~ j && c <~ k && d <~ l && e <~ m