-- |
-- Copyright   :  (c) Adrian Hey 2004-2008
-- License     :  BSD3
--
-- This module defines a useful variant of the "Prelude" `Ordering` data type.
--
-- Typically this data type is used as the result of a "combining comparison"
-- which combines values that are deemed to be equal (somehow). Note that the
-- functions defined here adhere to the same ordering convention as the overloaded
-- 'compare' (from the 'Ord' class):
--
-- @
-- a \`compare\` b -> LT (or Lt) implies a < b
-- a \`compare\` b -> GT (or Gt) implies a > b
-- @
--
-- The combinators exported from this module have a @CC@ suffix if they
-- return a combining comparison (most of them) and a @C@ suffix if they return
-- an ordinary comparison. All the combinators defined here are @INLINE@d, in the hope
-- that the compiler can avoid the overhead of using HOFs for frequently
-- used comparisons.
module Data.COrdering (
  COrdering (..),

  -- * Useful combinators
  unitCC,
  unitByCC,
  fstCC,
  fstByCC,
  sndCC,
  sndByCC,
  flipC,
  flipCC,

  -- ** For combining "equal" values with a user supplied function
  withCC,
  withCC',
  withByCC,
  withByCC',
) where

-- | Result of a combining comparison.
data COrdering a = Lt | Eq a | Gt deriving (COrdering a -> COrdering a -> Bool
(COrdering a -> COrdering a -> Bool)
-> (COrdering a -> COrdering a -> Bool) -> Eq (COrdering a)
forall a. Eq a => COrdering a -> COrdering a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall a. Eq a => COrdering a -> COrdering a -> Bool
== :: COrdering a -> COrdering a -> Bool
$c/= :: forall a. Eq a => COrdering a -> COrdering a -> Bool
/= :: COrdering a -> COrdering a -> Bool
Eq, Eq (COrdering a)
Eq (COrdering a) =>
(COrdering a -> COrdering a -> Ordering)
-> (COrdering a -> COrdering a -> Bool)
-> (COrdering a -> COrdering a -> Bool)
-> (COrdering a -> COrdering a -> Bool)
-> (COrdering a -> COrdering a -> Bool)
-> (COrdering a -> COrdering a -> COrdering a)
-> (COrdering a -> COrdering a -> COrdering a)
-> Ord (COrdering a)
COrdering a -> COrdering a -> Bool
COrdering a -> COrdering a -> Ordering
COrdering a -> COrdering a -> COrdering a
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall a. Ord a => Eq (COrdering a)
forall a. Ord a => COrdering a -> COrdering a -> Bool
forall a. Ord a => COrdering a -> COrdering a -> Ordering
forall a. Ord a => COrdering a -> COrdering a -> COrdering a
$ccompare :: forall a. Ord a => COrdering a -> COrdering a -> Ordering
compare :: COrdering a -> COrdering a -> Ordering
$c< :: forall a. Ord a => COrdering a -> COrdering a -> Bool
< :: COrdering a -> COrdering a -> Bool
$c<= :: forall a. Ord a => COrdering a -> COrdering a -> Bool
<= :: COrdering a -> COrdering a -> Bool
$c> :: forall a. Ord a => COrdering a -> COrdering a -> Bool
> :: COrdering a -> COrdering a -> Bool
$c>= :: forall a. Ord a => COrdering a -> COrdering a -> Bool
>= :: COrdering a -> COrdering a -> Bool
$cmax :: forall a. Ord a => COrdering a -> COrdering a -> COrdering a
max :: COrdering a -> COrdering a -> COrdering a
$cmin :: forall a. Ord a => COrdering a -> COrdering a -> COrdering a
min :: COrdering a -> COrdering a -> COrdering a
Ord, ReadPrec [COrdering a]
ReadPrec (COrdering a)
Int -> ReadS (COrdering a)
ReadS [COrdering a]
(Int -> ReadS (COrdering a))
-> ReadS [COrdering a]
-> ReadPrec (COrdering a)
-> ReadPrec [COrdering a]
-> Read (COrdering a)
forall a. Read a => ReadPrec [COrdering a]
forall a. Read a => ReadPrec (COrdering a)
forall a. Read a => Int -> ReadS (COrdering a)
forall a. Read a => ReadS [COrdering a]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: forall a. Read a => Int -> ReadS (COrdering a)
readsPrec :: Int -> ReadS (COrdering a)
$creadList :: forall a. Read a => ReadS [COrdering a]
readList :: ReadS [COrdering a]
$creadPrec :: forall a. Read a => ReadPrec (COrdering a)
readPrec :: ReadPrec (COrdering a)
$creadListPrec :: forall a. Read a => ReadPrec [COrdering a]
readListPrec :: ReadPrec [COrdering a]
Read, Int -> COrdering a -> ShowS
[COrdering a] -> ShowS
COrdering a -> String
(Int -> COrdering a -> ShowS)
-> (COrdering a -> String)
-> ([COrdering a] -> ShowS)
-> Show (COrdering a)
forall a. Show a => Int -> COrdering a -> ShowS
forall a. Show a => [COrdering a] -> ShowS
forall a. Show a => COrdering a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall a. Show a => Int -> COrdering a -> ShowS
showsPrec :: Int -> COrdering a -> ShowS
$cshow :: forall a. Show a => COrdering a -> String
show :: COrdering a -> String
$cshowList :: forall a. Show a => [COrdering a] -> ShowS
showList :: [COrdering a] -> ShowS
Show)

-- | A combining comparison for an instance of 'Ord' which returns unit @()@ where appropriate.
{-# INLINE unitCC #-}
unitCC :: Ord a => (a -> a -> COrdering ())
unitCC :: forall a. Ord a => a -> a -> COrdering ()
unitCC a
a a
b = case a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare a
a a
b of
  Ordering
LT -> COrdering ()
forall a. COrdering a
Lt
  Ordering
EQ -> () -> COrdering ()
forall a. a -> COrdering a
Eq ()
  Ordering
GT -> COrdering ()
forall a. COrdering a
Gt

-- | Create a combining comparison from an ordinary comparison by returning unit @()@ where appropriate.
{-# INLINE unitByCC #-}
unitByCC :: (a -> b -> Ordering) -> (a -> b -> COrdering ())
unitByCC :: forall a b. (a -> b -> Ordering) -> a -> b -> COrdering ()
unitByCC a -> b -> Ordering
cmp a
a b
b = case a -> b -> Ordering
cmp a
a b
b of
  Ordering
LT -> COrdering ()
forall a. COrdering a
Lt
  Ordering
EQ -> () -> COrdering ()
forall a. a -> COrdering a
Eq ()
  Ordering
GT -> COrdering ()
forall a. COrdering a
Gt

-- | A combining comparison for an instance of 'Ord' which keeps the first argument
-- if they are deemed equal. The second argument is discarded in this case.
{-# INLINE fstCC #-}
fstCC :: Ord a => (a -> a -> COrdering a)
fstCC :: forall a. Ord a => a -> a -> COrdering a
fstCC a
a a
a' = case a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare a
a a
a' of
  Ordering
LT -> COrdering a
forall a. COrdering a
Lt
  Ordering
EQ -> a -> COrdering a
forall a. a -> COrdering a
Eq a
a
  Ordering
GT -> COrdering a
forall a. COrdering a
Gt

-- | Create a combining comparison from an ordinary comparison by keeping the first argument
-- if they are deemed equal. The second argument is discarded in this case.
{-# INLINE fstByCC #-}
fstByCC :: (a -> b -> Ordering) -> (a -> b -> COrdering a)
fstByCC :: forall a b. (a -> b -> Ordering) -> a -> b -> COrdering a
fstByCC a -> b -> Ordering
cmp a
a b
b = case a -> b -> Ordering
cmp a
a b
b of
  Ordering
LT -> COrdering a
forall a. COrdering a
Lt
  Ordering
EQ -> a -> COrdering a
forall a. a -> COrdering a
Eq a
a
  Ordering
GT -> COrdering a
forall a. COrdering a
Gt

-- | A combining comparison for an instance of 'Ord' which keeps the second argument
-- if they are deemed equal. The first argument is discarded in this case.
{-# INLINE sndCC #-}
sndCC :: Ord a => (a -> a -> COrdering a)
sndCC :: forall a. Ord a => a -> a -> COrdering a
sndCC a
a a
a' = case a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare a
a a
a' of
  Ordering
LT -> COrdering a
forall a. COrdering a
Lt
  Ordering
EQ -> a -> COrdering a
forall a. a -> COrdering a
Eq a
a'
  Ordering
GT -> COrdering a
forall a. COrdering a
Gt

-- | Create a combining comparison from an ordinary comparison by keeping the second argument
-- if they are deemed equal. The first argument is discarded in this case.
{-# INLINE sndByCC #-}
sndByCC :: (a -> b -> Ordering) -> (a -> b -> COrdering b)
sndByCC :: forall a b. (a -> b -> Ordering) -> a -> b -> COrdering b
sndByCC a -> b -> Ordering
cmp a
a b
b = case a -> b -> Ordering
cmp a
a b
b of
  Ordering
LT -> COrdering b
forall a. COrdering a
Lt
  Ordering
EQ -> b -> COrdering b
forall a. a -> COrdering a
Eq b
b
  Ordering
GT -> COrdering b
forall a. COrdering a
Gt

-- | Create a combining comparison using the supplied combining function, which is applied if
-- 'compare' returns 'EQ'. See 'withCC'' for a stricter version of this function.
{-# INLINE withCC #-}
withCC :: Ord a => (a -> a -> b) -> (a -> a -> COrdering b)
withCC :: forall a b. Ord a => (a -> a -> b) -> a -> a -> COrdering b
withCC a -> a -> b
f a
a a
a' = case a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare a
a a
a' of
  Ordering
LT -> COrdering b
forall a. COrdering a
Lt
  Ordering
EQ -> b -> COrdering b
forall a. a -> COrdering a
Eq (a -> a -> b
f a
a a
a')
  Ordering
GT -> COrdering b
forall a. COrdering a
Gt

-- | Same as 'withCC', except the combining function is applied strictly.
{-# INLINE withCC' #-}
withCC' :: Ord a => (a -> a -> b) -> (a -> a -> COrdering b)
withCC' :: forall a b. Ord a => (a -> a -> b) -> a -> a -> COrdering b
withCC' a -> a -> b
f a
a a
a' = case a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare a
a a
a' of
  Ordering
LT -> COrdering b
forall a. COrdering a
Lt
  Ordering
EQ -> let b :: b
b = a -> a -> b
f a
a a
a' in b
b b -> COrdering b -> COrdering b
forall a b. a -> b -> b
`seq` b -> COrdering b
forall a. a -> COrdering a
Eq b
b
  Ordering
GT -> COrdering b
forall a. COrdering a
Gt

-- | Create a combining comparison using the supplied comparison and combining function,
-- which is applied if the comparison returns 'EQ'. See 'withByCC'' for a stricter version
-- of this function.
{-# INLINE withByCC #-}
withByCC :: (a -> b -> Ordering) -> (a -> b -> c) -> (a -> b -> COrdering c)
withByCC :: forall a b c.
(a -> b -> Ordering) -> (a -> b -> c) -> a -> b -> COrdering c
withByCC a -> b -> Ordering
cmp a -> b -> c
f a
a b
b = case a -> b -> Ordering
cmp a
a b
b of
  Ordering
LT -> COrdering c
forall a. COrdering a
Lt
  Ordering
EQ -> c -> COrdering c
forall a. a -> COrdering a
Eq (a -> b -> c
f a
a b
b)
  Ordering
GT -> COrdering c
forall a. COrdering a
Gt

-- | Same as 'withByCC', except the combining function is applied strictly.
{-# INLINE withByCC' #-}
withByCC' :: (a -> b -> Ordering) -> (a -> b -> c) -> (a -> b -> COrdering c)
withByCC' :: forall a b c.
(a -> b -> Ordering) -> (a -> b -> c) -> a -> b -> COrdering c
withByCC' a -> b -> Ordering
cmp a -> b -> c
f a
a b
b = case a -> b -> Ordering
cmp a
a b
b of
  Ordering
LT -> COrdering c
forall a. COrdering a
Lt
  Ordering
EQ -> let c :: c
c = a -> b -> c
f a
a b
b in c
c c -> COrdering c -> COrdering c
forall a b. a -> b -> b
`seq` c -> COrdering c
forall a. a -> COrdering a
Eq c
c
  Ordering
GT -> COrdering c
forall a. COrdering a
Gt

-- | Converts a comparison to one which takes arguments in flipped order, but
-- preserves the ordering that would be given by the "unflipped" version (disregarding type issues).
-- So it's not the same as using the prelude 'flip' (which would reverse the ordering too).
{-# INLINE flipC #-}
flipC :: (a -> b -> Ordering) -> (b -> a -> Ordering)
flipC :: forall a b. (a -> b -> Ordering) -> b -> a -> Ordering
flipC a -> b -> Ordering
cmp b
b a
a = case a -> b -> Ordering
cmp a
a b
b of
  Ordering
LT -> Ordering
GT
  Ordering
EQ -> Ordering
EQ
  Ordering
GT -> Ordering
LT

-- | Converts a combining comparison to one which takes arguments in flipped order, but
-- preserves the ordering that would be given by the "unflipped" version (disregarding type issues).
-- So it's not the same as using the prelude 'flip' (which would reverse the ordering too).
{-# INLINE flipCC #-}
flipCC :: (a -> b -> COrdering c) -> (b -> a -> COrdering c)
flipCC :: forall a b c. (a -> b -> COrdering c) -> b -> a -> COrdering c
flipCC a -> b -> COrdering c
cmp b
b a
a = case a -> b -> COrdering c
cmp a
a b
b of
  COrdering c
Lt -> COrdering c
forall a. COrdering a
Gt
  e :: COrdering c
e@(Eq c
_) -> COrdering c
e
  COrdering c
Gt -> COrdering c
forall a. COrdering a
Lt