{-# LANGUAGE LinearTypes #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE LambdaCase #-}

module Data.Ord.Linear.Internal.Ord
  ( Ord(..)
  , Ordering(..)
  , min
  , max
  )
  where

import Data.Ord.Linear.Internal.Eq
import qualified Prelude
import Prelude.Linear.Internal
import Data.Ord (Ordering(..))
import Data.Bool.Linear ( Bool (..), not )
import Data.Unrestricted.Linear
import Data.Monoid.Linear

-- | Linear Orderings
--
-- Linear orderings provide a strict order. The laws for @(<=)@ for
-- all \(a,b,c\):
--
-- * reflexivity: \(a \leq a \)
-- * antisymmetry: \((a \leq b) \land (b \leq a) \rightarrow (a = b) \)
-- * transitivity: \((a \leq b) \land (b \leq c) \rightarrow (a \leq c) \)
--
-- and these \"agree\" with @<@:
--
-- * @x <= y@ = @not (y > x)@
-- * @x >= y@ = @not (y < x)@
--
-- Unlike in the non-linear setting, a linear @compare@ doesn't follow from
-- @<=@ since it requires calls: one to @<=@ and one to @==@. However,
-- from a linear @compare@ it is easy to implement the others. Hence, the
-- minimal complete definition only contains @compare@.
class Eq a => Ord a where
  {-# MINIMAL compare #-}

  -- | @compare x y@ returns an @Ordering@ which is
  -- one of @GT@ (greater than), @EQ@ (equal), or @LT@ (less than)
  -- which should be understood as \"x is @(compare x y)@ y\".
  compare :: a %1-> a %1-> Ordering

  (<=) :: a %1-> a %1-> Bool
  a
x <= a
y = Bool %1 -> Bool
not (a
x a %1 -> a %1 -> Bool
forall a. Ord a => a %1 -> a %1 -> Bool
> a
y)

  (<) :: a %1-> a %1-> Bool
  a
x < a
y = a %1 -> a %1 -> Ordering
forall a. Ord a => a %1 -> a %1 -> Ordering
compare a
x a
y Ordering %1 -> Ordering %1 -> Bool
forall a. Eq a => a %1 -> a %1 -> Bool
== Ordering
LT

  (>) :: a %1-> a %1-> Bool
  a
x > a
y = a %1 -> a %1 -> Ordering
forall a. Ord a => a %1 -> a %1 -> Ordering
compare a
x a
y Ordering %1 -> Ordering %1 -> Bool
forall a. Eq a => a %1 -> a %1 -> Bool
== Ordering
GT

  (>=) :: a %1-> a %1-> Bool
  a
x >= a
y = Bool %1 -> Bool
not (a
x a %1 -> a %1 -> Bool
forall a. Ord a => a %1 -> a %1 -> Bool
< a
y)

  infix 4 <=, <, >, >=


-- | @max x y@ returns the larger input, or  'y'
-- in case of a tie.
max :: (Dupable a, Ord a) =>  a %1-> a %1-> a
max :: forall a. (Dupable a, Ord a) => a %1 -> a %1 -> a
max a
x a
y =
  a %1 -> (a, a)
forall a. Dupable a => a %1 -> (a, a)
dup2 a
x (a, a) %1 -> ((a, a) %1 -> a) %1 -> a
forall a b. a %1 -> (a %1 -> b) %1 -> b
& \(a
x', a
x'') ->
    a %1 -> (a, a)
forall a. Dupable a => a %1 -> (a, a)
dup2 a
y (a, a) %1 -> ((a, a) %1 -> a) %1 -> a
forall a b. a %1 -> (a %1 -> b) %1 -> b
& \(a
y', a
y'') ->
      if a
x' a %1 -> a %1 -> Bool
forall a. Ord a => a %1 -> a %1 -> Bool
<= a
y'
      then a
x'' a %1 -> a %1 -> a
forall a b. Consumable a => a %1 -> b %1 -> b
`lseq` a
y''
      else a
y'' a %1 -> a %1 -> a
forall a b. Consumable a => a %1 -> b %1 -> b
`lseq` a
x''

-- | @min x y@ returns the smaller input, or 'y'
-- in case of a tie.
min :: (Dupable a, Ord a) =>  a %1-> a %1-> a
min :: forall a. (Dupable a, Ord a) => a %1 -> a %1 -> a
min a
x a
y =
  a %1 -> (a, a)
forall a. Dupable a => a %1 -> (a, a)
dup2 a
x (a, a) %1 -> ((a, a) %1 -> a) %1 -> a
forall a b. a %1 -> (a %1 -> b) %1 -> b
& \(a
x', a
x'') ->
    a %1 -> (a, a)
forall a. Dupable a => a %1 -> (a, a)
dup2 a
y (a, a) %1 -> ((a, a) %1 -> a) %1 -> a
forall a b. a %1 -> (a %1 -> b) %1 -> b
& \(a
y', a
y'') ->
      if a
x' a %1 -> a %1 -> Bool
forall a. Ord a => a %1 -> a %1 -> Bool
<= a
y'
      then a
y'' a %1 -> a %1 -> a
forall a b. Consumable a => a %1 -> b %1 -> b
`lseq` a
x''
      else a
x'' a %1 -> a %1 -> a
forall a b. Consumable a => a %1 -> b %1 -> b
`lseq` a
y''

-- * Instances

instance Prelude.Ord a => Ord (Ur a) where
  Ur a
x compare :: Ur a %1 -> Ur a %1 -> Ordering
`compare` Ur a
y = a
x a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
`Prelude.compare` a
y

instance (Consumable a, Ord a) => Ord (Prelude.Maybe a) where
  Maybe a
Prelude.Nothing compare :: Maybe a %1 -> Maybe a %1 -> Ordering
`compare` Maybe a
Prelude.Nothing = Ordering
EQ
  Maybe a
Prelude.Nothing `compare` Prelude.Just a
y = a
y a %1 -> Ordering %1 -> Ordering
forall a b. Consumable a => a %1 -> b %1 -> b
`lseq` Ordering
LT
  Prelude.Just a
x `compare` Maybe a
Prelude.Nothing = a
x a %1 -> Ordering %1 -> Ordering
forall a b. Consumable a => a %1 -> b %1 -> b
`lseq` Ordering
GT
  Prelude.Just a
x `compare` Prelude.Just a
y = a
x a %1 -> a %1 -> Ordering
forall a. Ord a => a %1 -> a %1 -> Ordering
`compare` a
y

instance (Consumable a, Consumable b, Ord a, Ord b)
  => Ord (Prelude.Either a b) where
  Prelude.Left a
x compare :: Either a b %1 -> Either a b %1 -> Ordering
`compare` Prelude.Right b
y = (a
x, b
y) (a, b) %1 -> Ordering %1 -> Ordering
forall a b. Consumable a => a %1 -> b %1 -> b
`lseq` Ordering
LT
  Prelude.Right b
x `compare` Prelude.Left a
y = (b
x, a
y) (b, a) %1 -> Ordering %1 -> Ordering
forall a b. Consumable a => a %1 -> b %1 -> b
`lseq` Ordering
GT
  Prelude.Left a
x `compare` Prelude.Left a
y = a
x a %1 -> a %1 -> Ordering
forall a. Ord a => a %1 -> a %1 -> Ordering
`compare` a
y
  Prelude.Right b
x `compare` Prelude.Right b
y = b
x b %1 -> b %1 -> Ordering
forall a. Ord a => a %1 -> a %1 -> Ordering
`compare` b
y

instance (Consumable a, Ord a) => Ord [a] where
  {-# SPECIALISE instance Ord [Prelude.Char] #-}
  compare :: [a] %1 -> [a] %1 -> Ordering
compare [] [] = Ordering
EQ
  compare [a]
xs [] = [a]
xs [a] %1 -> Ordering %1 -> Ordering
forall a b. Consumable a => a %1 -> b %1 -> b
`lseq` Ordering
GT
  compare [] [a]
ys = [a]
ys [a] %1 -> Ordering %1 -> Ordering
forall a b. Consumable a => a %1 -> b %1 -> b
`lseq` Ordering
LT
  compare (a
x:[a]
xs) (a
y:[a]
ys) =
    a %1 -> a %1 -> Ordering
forall a. Ord a => a %1 -> a %1 -> Ordering
compare a
x a
y Ordering %1 -> (Ordering %1 -> Ordering) %1 -> Ordering
forall a b. a %1 -> (a %1 -> b) %1 -> b
& \case
      Ordering
EQ -> [a] %1 -> [a] %1 -> Ordering
forall a. Ord a => a %1 -> a %1 -> Ordering
compare [a]
xs [a]
ys
      Ordering
res -> ([a]
xs, [a]
ys) ([a], [a]) %1 -> Ordering %1 -> Ordering
forall a b. Consumable a => a %1 -> b %1 -> b
`lseq` Ordering
res

instance (Ord a, Ord b) => Ord (a, b) where
  (a
a, b
b) compare :: (a, b) %1 -> (a, b) %1 -> Ordering
`compare` (a
a', b
b') =
    a %1 -> a %1 -> Ordering
forall a. Ord a => a %1 -> a %1 -> Ordering
compare a
a a
a' Ordering %1 -> Ordering %1 -> Ordering
forall a. Semigroup a => a %1 -> a %1 -> a
<> b %1 -> b %1 -> Ordering
forall a. Ord a => a %1 -> a %1 -> Ordering
compare b
b b
b'

instance (Ord a, Ord b, Ord c) => Ord (a, b, c) where
  (a
a, b
b, c
c) compare :: (a, b, c) %1 -> (a, b, c) %1 -> Ordering
`compare` (a
a', b
b', c
c') =
    a %1 -> a %1 -> Ordering
forall a. Ord a => a %1 -> a %1 -> Ordering
compare a
a a
a' Ordering %1 -> Ordering %1 -> Ordering
forall a. Semigroup a => a %1 -> a %1 -> a
<> b %1 -> b %1 -> Ordering
forall a. Ord a => a %1 -> a %1 -> Ordering
compare b
b b
b' Ordering %1 -> Ordering %1 -> Ordering
forall a. Semigroup a => a %1 -> a %1 -> a
<> c %1 -> c %1 -> Ordering
forall a. Ord a => a %1 -> a %1 -> Ordering
compare c
c c
c'

instance (Ord a, Ord b, Ord c, Ord d) => Ord (a, b, c, d) where
  (a
a, b
b, c
c, d
d) compare :: (a, b, c, d) %1 -> (a, b, c, d) %1 -> Ordering
`compare` (a
a', b
b', c
c', d
d') =
    a %1 -> a %1 -> Ordering
forall a. Ord a => a %1 -> a %1 -> Ordering
compare a
a a
a' Ordering %1 -> Ordering %1 -> Ordering
forall a. Semigroup a => a %1 -> a %1 -> a
<> b %1 -> b %1 -> Ordering
forall a. Ord a => a %1 -> a %1 -> Ordering
compare b
b b
b' Ordering %1 -> Ordering %1 -> Ordering
forall a. Semigroup a => a %1 -> a %1 -> a
<> c %1 -> c %1 -> Ordering
forall a. Ord a => a %1 -> a %1 -> Ordering
compare c
c c
c' Ordering %1 -> Ordering %1 -> Ordering
forall a. Semigroup a => a %1 -> a %1 -> a
<> d %1 -> d %1 -> Ordering
forall a. Ord a => a %1 -> a %1 -> Ordering
compare d
d d
d'

deriving via MovableOrd () instance Ord ()
deriving via MovableOrd Prelude.Int instance Ord Prelude.Int
deriving via MovableOrd Prelude.Double instance Ord Prelude.Double
deriving via MovableOrd Prelude.Bool instance Ord Prelude.Bool
deriving via MovableOrd Prelude.Char instance Ord Prelude.Char
deriving via MovableOrd Prelude.Ordering instance Ord Prelude.Ordering

newtype MovableOrd a = MovableOrd a

instance (Prelude.Eq a, Movable a) => Eq (MovableOrd a) where
  MovableOrd a
ar == :: MovableOrd a %1 -> MovableOrd a %1 -> Bool
== MovableOrd a
br
    = (a, a) %1 -> Ur (a, a)
forall a. Movable a => a %1 -> Ur a
move (a
ar, a
br) Ur (a, a) %1 -> (Ur (a, a) %1 -> Bool) %1 -> Bool
forall a b. a %1 -> (a %1 -> b) %1 -> b
& \(Ur (a
a, a
b)) ->
        a
a a -> a -> Bool
forall a. Eq a => a -> a -> Bool
Prelude.== a
b

  MovableOrd a
ar /= :: MovableOrd a %1 -> MovableOrd a %1 -> Bool
/= MovableOrd a
br
    = (a, a) %1 -> Ur (a, a)
forall a. Movable a => a %1 -> Ur a
move (a
ar, a
br) Ur (a, a) %1 -> (Ur (a, a) %1 -> Bool) %1 -> Bool
forall a b. a %1 -> (a %1 -> b) %1 -> b
& \(Ur (a
a, a
b)) ->
        a
a a -> a -> Bool
forall a. Eq a => a -> a -> Bool
Prelude./= a
b

instance (Prelude.Ord a, Movable a) => Ord (MovableOrd a) where
  MovableOrd a
ar compare :: MovableOrd a %1 -> MovableOrd a %1 -> Ordering
`compare` MovableOrd a
br
    = (a, a) %1 -> Ur (a, a)
forall a. Movable a => a %1 -> Ur a
move (a
ar, a
br) Ur (a, a) %1 -> (Ur (a, a) %1 -> Ordering) %1 -> Ordering
forall a b. a %1 -> (a %1 -> b) %1 -> b
& \(Ur (a
a, a
b)) ->
        a
a a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
`Prelude.compare` a
b