{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
module Data.Poset.Internal where
import qualified Data.List as List
import qualified GHC.Types as Types
import qualified Prelude
import Prelude hiding (Ordering(..), Ord(..))
import Data.Semigroup
import Data.Monoid
data Ordering = LT | EQ | GT | NC
deriving (Eq, Show, Read, Bounded, Enum)
instance Semigroup Ordering where
EQ <> x = x
NC <> _ = NC
LT <> _ = LT
GT <> _ = GT
instance Monoid Ordering where
mempty = EQ
totalOrder :: Ordering -> Types.Ordering
totalOrder LT = Types.LT
totalOrder EQ = Types.EQ
totalOrder GT = Types.GT
totalOrder NC = error "Uncomparable elements in total order."
partialOrder :: Types.Ordering -> Ordering
partialOrder Types.LT = LT
partialOrder Types.EQ = EQ
partialOrder Types.GT = GT
class Eq a => Poset a where
compare :: a -> a -> Ordering
(<==>) :: a -> a -> Bool
(</=>) :: a -> a -> Bool
(<) :: a -> a -> Bool
(<=) :: a -> a -> Bool
(>=) :: a -> a -> Bool
(>) :: a -> a -> Bool
a `compare` b
| a == b = EQ
| a <= b = LT
| b <= a = GT
| otherwise = NC
a < b = a `compare` b == LT
a > b = a `compare` b == GT
a <==> b = a `compare` b /= NC
a </=> b = a `compare` b == NC
a <= b = a < b || a `compare` b == EQ
a >= b = a > b || a `compare` b == EQ
class Poset a => Sortable a where
sortBy :: (a -> a -> Ordering) -> [a] -> [a]
isOrdered :: a -> Bool
max :: a -> a -> a
min :: a -> a -> a
sortBy f = List.sortBy ((totalOrder .) . f) . filter isOrdered
max a b = case a `compare` b of
LT -> b
EQ -> a
GT -> a
NC -> if isOrdered a then a else if isOrdered b then b else a
min a b = case a `compare` b of
LT -> a
EQ -> b
GT -> b
NC -> if isOrdered a then a else if isOrdered b then b else a
class Sortable a => Ord a
instance {-# OVERLAPS #-} (Eq a, Data.Poset.Internal.Ord a) => Prelude.Ord a where
compare = (totalOrder .) . compare
(<) = (<)
(<=) = (<=)
(>=) = (>=)
(>) = (>)
min = min
max = max