-- | <https://en.wikipedia.org/wiki/Partially_ordered_set#Intervals>
module Data.Dioid.Interval (
    Interval()
  , (...)
  , endpts
  , singleton
  , upset
  , dnset
  , empty
) where

import Data.Prd
import Data.Prd.Lattice
import Data.Connection

import Prelude

{-

ivllat :: (Lattice a, Bound a) => Trip (Interval a) a
ivllat = Trip f g h where
  f = maybe minimal (uncurry (\/)) . endpts
  g = singleton
  h = maybe maximal (uncurry (/\)) . endpts 

indexed :: Index a => Conn (Interval a) (Maybe (Down a, a))

https://en.wikipedia.org/wiki/Locally_finite_poset
https://en.wikipedia.org/wiki/Incidence_algebra

An interval in a poset P is a subset I of P with the property that, for any x and y in I and any z in P, if x ≤ z ≤ y, then z is also in I. 

-}

data Interval a = I !a !a | Empty deriving (Eq, Show)

-- Interval order
-- https://en.wikipedia.org/wiki/Interval_order
instance Ord a => Prd (Interval a) where
  Empty <~ Empty = True
  Empty <~ _ = False

  i@(I _ x) <~ j@(I y _) = x < y || i == j

{-
-- Containment order
-- https://en.wikipedia.org/wiki/Containment_order
instance Prd a => Prd (Interval a) where
  Empty <~ _ = True
  I x y <~ I x' y' = x' <~ x && y <~ y'
-}


infix 3 ...

-- | Construct an interval from a pair of points.
--
-- If @a <~ b@ then @a ... b = Empty@.
--
(...) :: Prd a => a -> a -> Interval a
a ... b
  | a <~ b = I a b
  | otherwise = Empty
{-# INLINE (...) #-}

-- | Obtain the endpoints of an interval.
--
endpts :: Interval a -> Maybe (a, a)
endpts Empty = Nothing
endpts (I x y) = Just (x, y)
{-# INLINE endpts #-}

-- | Construct an interval containing a single point.
--
-- >>> singleton 1
-- 1 ... 1
--
singleton :: a -> Interval a
singleton a = I a a
{-# INLINE singleton #-}

{-
properties: 

Yoneda lemma for preorders:
x <~ y <==> upset x <~ upset y --containment order

-}

-- | \( X_\geq(x) = \{ y \in X | y \geq x \} \)
--
-- Construct the upper set of an element /x/.
--
-- This function is monotone wrt the containment order.
--
upset :: Max a => a -> Interval a
upset x = x ... maximal
{-# INLINE upset #-}

-- | \( X_\leq(x) = \{ y \in X | y \leq x \} \)
--
-- Construct the lower set of an element /x/.
--
-- This function is antitone wrt the containment order.
--
dnset :: Min a => a -> Interval a
dnset x = minimal ... x
{-# INLINE dnset #-}

-- | The empty interval.
--
-- >>> empty
-- Empty
empty :: Interval a
empty = Empty
{-# INLINE empty #-}