{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} module Relation.Binary.Comparison where import Prelude (Integer) import qualified Prelude import Algebra import Control.Applicative import Control.Monad import Data.Bool import Data.Either import Data.Function (flip, on) import Data.Maybe import Data.Ord (Ordering (..)) import Numeric.Natural class Preord a where (≤), (≥), (<), (>) :: a -> a -> Bool (≤) = flip (≥) (≥) = flip (≤) a < b = a ≤ b && not (a ≥ b) (>) = flip (<) class PartialEq a where (≡), (≢) :: a -> a -> Bool a ≡ b = not (a ≢ b) a ≢ b = not (a ≡ b) class (Preord a, PartialEq a) => Eq a class (Preord a, PartialEq a) => PartialOrd a where tryCompare :: a -> a -> Maybe Ordering tryCompare a b = case (a ≤ b, b ≤ a) of (False, False) -> Nothing (False, True) -> Just GT (True, False) -> Just LT (True, True) -> Just EQ class (PartialOrd a, Eq a) => Ord a where compare :: a -> a -> Ordering compare a b = fromJust (tryCompare a b) instance Preord () where () ≤ () = True instance PartialEq () where () ≡ () = True instance PartialOrd () where tryCompare () () = Just EQ instance Eq () instance Ord () instance Preord Bool where (≤) = (Prelude.<=) instance PartialEq Bool where (≡) = (Prelude.==) instance PartialOrd Bool where tryCompare a b = Just (Prelude.compare a b) instance Eq Bool instance Ord Bool instance Preord Ordering where (≤) = (Prelude.<=) instance PartialEq Ordering where (≡) = (Prelude.==) instance PartialOrd Ordering where tryCompare a b = Just (Prelude.compare a b) instance Eq Ordering instance Ord Ordering instance Preord Natural where (≤) = (Prelude.<=) (<) = (Prelude.<) instance PartialEq Natural where (≡) = (Prelude.==) instance PartialOrd Natural where tryCompare a b = Just (Prelude.compare a b) instance Eq Natural instance Ord Natural instance Preord Integer where (≤) = (Prelude.<=) (<) = (Prelude.<) instance PartialEq Integer where (≡) = (Prelude.==) instance PartialOrd Integer where tryCompare a b = Just (Prelude.compare a b) instance Eq Integer instance Ord Integer instance (PartialEq a, PartialEq b) => PartialEq (a, b) where (aₗ, bₗ) ≡ (aᵣ, bᵣ) = aₗ ≡ aᵣ && bₗ ≡ bᵣ instance (Preord a, Preord b) => Preord (a, b) where (aₗ, bₗ) ≤ (aᵣ, bᵣ) = aₗ ≤ aᵣ && bₗ ≤ bᵣ instance (PartialOrd a, PartialOrd b) => PartialOrd (a, b) where tryCompare (aₗ, bₗ) (aᵣ, bᵣ) = liftA2 (,) (tryCompare aₗ aᵣ) (tryCompare bₗ bᵣ) >>= \ case (EQ, y) -> Just y (x, EQ) -> Just x (LT, LT) -> Just LT (GT, GT) -> Just GT _ -> Nothing instance (PartialOrd a, PartialOrd b) => Preord (Lexical (a, b)) where a ≤ b = Just GT ≢ tryCompare a b a < b = Just LT ≡ tryCompare a b instance (PartialOrd a, PartialOrd b) => PartialOrd (Lexical (a, b)) where Lexical (aₗ, bₗ) `tryCompare` Lexical (aᵣ, bᵣ) = tryCompare aₗ aᵣ <> tryCompare bₗ bᵣ instance (PartialOrd a, PartialOrd b, Eq a, Eq b) => Eq (Lexical (a, b)) instance (Ord a, Ord b) => Ord (Lexical (a, b)) instance (Preord a, Preord b) => Preord (Either a b) where Left x ≤ Left y = x ≤ y Right x ≤ Right y = x ≤ y _ ≤ _ = False instance (PartialEq a, PartialEq b) => PartialEq (Either a b) where Left x ≡ Left y = x ≡ y Right x ≡ Right y = x ≡ y _ ≡ _ = False instance (PartialOrd a, PartialOrd b) => PartialOrd (Either a b) where Left x `tryCompare` Left y = x `tryCompare` y Right x `tryCompare` Right y = x `tryCompare` y _ `tryCompare` _ = Nothing instance (Preord a, Preord b) => Preord (Lexical (Either a b)) where Lexical (Left _) ≤ Lexical (Right _) = True Lexical x ≤ Lexical y = x ≤ y instance (PartialOrd a, PartialOrd b) => PartialOrd (Lexical (Either a b)) where Lexical (Left _) `tryCompare` Lexical (Right _) = Just LT Lexical (Right _) `tryCompare` Lexical (Left _) = Just GT Lexical x `tryCompare` Lexical y = tryCompare x y instance (Eq a, Eq b) => Eq (Lexical (Either a b)) instance (Ord a, Ord b) => Ord (Lexical (Either a b)) newtype Lexical a = Lexical a deriving (PartialEq, Semigroup, Monoid, Group) instance PartialEq a => PartialEq (Maybe a) where (≡) = (≡) `on` maybe (Left ()) Right instance Preord a => Preord (Maybe a) where (≤) = (≤) `on` maybe (Left ()) Right instance PartialOrd a => PartialOrd (Maybe a) where tryCompare = tryCompare `on` maybe (Left ()) Right instance Eq a => Eq (Maybe a)