||| An strict preorder (sometimes known as a quasi-order, or an
||| ordering) is what you get when you remove the diagonal `{(a,b) | a
||| r b , b r a}` from a preorder. For example a < b is an ordering.
||| This module extends base's Control.Order with the strict versions.
||| The interface system seems to struggle a bit with some of the constructions,
||| so I hacked them a bit. Sorry.
module Decidable.Order.Strict

import Control.Relation
import Control.Order
import Decidable.Equality

%default total

public export
interface Irreflexive ty rel where
  irreflexive : {x : ty} -> Not (rel x x)

public export
interface (Transitive ty rel, Irreflexive ty rel) => StrictPreorder  ty rel where

public export
interface Asymmetric ty rel where
  asymmetric : {x, y : ty} -> rel x y -> Not (rel y x)

public export
[SPA] StrictPreorder ty rel => Asymmetric ty rel where
  asymmetric xy yx = irreflexive {rel} $ transitive {rel} xy yx

-- We make this completion a record type so that we do not need to name the
-- interface implementations for fear of them interfering with other
-- `Either`-based constructions.

public export
record EqOr {0 t : Type} (spo : Rel t) (a, b : t) where
  constructor MkEqOr
  runEqOr : Either (a = b) (a `spo` b)

public export
Transitive ty rel => Transitive ty (EqOr rel) where

  transitive (MkEqOr (Left  Refl)) bLTEc                 = bLTEc
  transitive aLTEb                 (MkEqOr (Left  Refl)) = aLTEb
  transitive (MkEqOr (Right aLTb)) (MkEqOr (Right bLTc))
    = MkEqOr $ Right $ transitive {rel} aLTb bLTc

public export
Reflexive ty (EqOr rel) where
  reflexive = MkEqOr $ Left Refl

public export
Transitive ty rel => Preorder ty (EqOr rel) where

public export
(Irreflexive ty rel, Asymmetric ty rel) => Antisymmetric ty (EqOr rel) where

  antisymmetric (MkEqOr p) (MkEqOr q) = go p q where

    go : {a, b : ty} ->
         Either (a = b) (a `rel` b) ->
         Either (b = a) (b `rel` a) ->
         a = b
    go (Left  Refl) (Left  Refl) = Refl
    go (Left  Refl) (Right bLTa) = absurd (irreflexive {rel} bLTa)
    go (Right aLTb) (Left  Refl) = absurd (irreflexive {rel} aLTb)
    go (Right aLTb) (Right bLTa) = absurd (asymmetric {rel} aLTb bLTa)

public export
(Irreflexive ty rel, Asymmetric ty rel, Transitive ty rel) =>
  PartialOrder ty (EqOr rel) where

public export
data DecOrdering : {lt : t -> t -> Type} -> (a,b : t) -> Type where
  DecLT : forall lt . (a `lt` b) -> DecOrdering {lt = lt} a b
  DecEQ : forall lt . (a  =   b) -> DecOrdering {lt = lt} a b
  DecGT : forall lt . (b `lt` a) -> DecOrdering {lt = lt} a b

public export
interface StrictPreorder t spo => StrictOrdered t spo where
  order : (a,b : t) -> DecOrdering {lt = spo} a b

public export
Connex ty rel => Connex ty (EqOr rel) where
  connex neq = bimap (MkEqOr . Right) (MkEqOr . Right) (connex neq)

public export
(Connex ty rel, DecEq ty) => StronglyConnex ty (EqOr rel) where
  order a b = case decEq a b of
    Yes eq => Left $ MkEqOr (Left eq)
    No neq => connex neq
