module Data.Interval where
import Control.DeepSeq (NFData(..))
import Data.Bool
import Data.Data (Data(..))
import Data.Eq (Eq(..))
import Data.Foldable (concat)
import Data.Function (($), flip)
import Data.Functor (Functor(..))
import qualified Data.Functor as Functor
import Data.Maybe (Maybe(..))
import Data.Ord (Ord(..), Ordering(..))
import Data.Tuple
import Data.Typeable (Typeable)
import Prelude (Bounded(..), seq)
import Text.Show (Show(..))
data Limit x
= Limit
{ adherence :: Adherence
, limit :: x }
deriving (Eq, Data, Show, Typeable)
instance Functor Limit where
fmap f (Limit a x) = Limit a (f x)
instance NFData x => NFData (Limit x) where
rnf (Limit _a l) = rnf l
data Adherence = Out | In
deriving (Eq, Data, Show, Typeable)
flip_limit :: Limit x -> Limit x
flip_limit (Limit a x) = Limit (case a of { In -> Out; Out -> In }) x
newtype LL x = LL { unLL :: x }
deriving (Eq)
instance Ord x => Ord (LL (Limit x)) where
compare (LL x) (LL y) =
case compare (limit x) (limit y) of
EQ ->
case (adherence x, adherence y) of
(Out, In ) -> GT
(In , Out) -> LT
_ -> EQ
o -> o
newtype HH x = HH { unHH :: x }
deriving (Eq)
instance Ord x => Ord (HH (Limit x)) where
compare (HH x) (HH y) =
case compare (limit x) (limit y) of
EQ ->
case (adherence x, adherence y) of
(Out, In ) -> LT
(In , Out) -> GT
_ -> EQ
o -> o
newtype Ord x
=> Interval x
= Interval (Limit x, Limit x)
deriving (Eq, Show, Data, Typeable)
instance (NFData x, Ord x) => NFData (Interval x) where
rnf (Interval (x, y)) = rnf x `seq` rnf y
low :: Ord x => Interval x -> Limit x
low (Interval t) = fst t
high :: Ord x => Interval x -> Limit x
high (Interval t) = snd t
interval :: Ord x => Limit x -> Limit x -> Maybe (Interval x)
interval x y =
case compare_without_adherence x y of
LT -> Just $ Interval (x, y)
EQ ->
case (adherence x, adherence y) of
(In, In) -> Just $ Interval (x, y)
_ -> Nothing
GT -> Nothing
fmap :: (Ord x, Ord y) => (x -> y) -> Interval x -> Maybe (Interval y)
fmap f (Interval (il, ih)) = interval (Functor.fmap f il) (Functor.fmap f ih)
fmap_unsafe :: (Ord x, Ord y) => (x -> y) -> Interval x -> Interval y
fmap_unsafe f (Interval (il, ih)) = Interval (Functor.fmap f il, Functor.fmap f ih)
instance Ord x => Ord (Interval x) where
compare (Interval (il, ih)) (Interval (jl, jh)) =
case compare (LL il) (LL jl) of
EQ -> compare (HH ih) (HH jh)
o -> o
limits :: Ord x => Interval x -> (Limit x, Limit x)
limits (Interval t) = t
point :: Ord x => x -> Interval x
point x = Interval (Limit In x, Limit In x)
flip_limits :: Ord x => Interval x -> Interval x
flip_limits (Interval (l, h)) = Interval (flip_limit l, flip_limit h)
compare_without_adherence :: Ord x => Limit x -> Limit x -> Ordering
compare_without_adherence (Limit _ x) (Limit _ y) = compare x y
locate :: Ord x => x -> Interval x -> Ordering
locate x (Interval (l, h)) =
case compare x (limit l) of
LT -> LT
EQ | adherence l == In -> EQ
EQ -> LT
GT ->
case compare x (limit h) of
LT -> EQ
EQ | adherence h == In -> EQ
EQ -> GT
GT -> GT
within :: Ord x => x -> Interval x -> Bool
within x i = locate x i == EQ
into :: Ord x => Interval x -> Interval x -> Bool
into i j =
case position i j of
(Prefix , LT) -> True
(Suffixed, GT) -> True
(Include , GT) -> True
(Equal , _) -> True
_ -> False
onto :: Ord x => Interval x -> Interval x -> Bool
onto = flip into
infix 5 <=..<=
(<=..<=) :: Ord x => x -> x -> Maybe (Interval x)
(<=..<=) x y =
case compare x y of
LT -> Just $ Interval (Limit In x, Limit In y)
EQ -> Just $ Interval (Limit In x, Limit In y)
GT -> Nothing
infix 5 <..<=
(<..<=) :: Ord x => x -> x -> Maybe (Interval x)
(<..<=) x y =
case compare x y of
LT -> Just $ Interval (Limit Out x, Limit In y)
EQ -> Nothing
GT -> Nothing
infix 5 <=..<
(<=..<) :: Ord x => x -> x -> Maybe (Interval x)
(<=..<) x y =
case compare x y of
LT -> Just $ Interval (Limit In x, Limit Out y)
EQ -> Nothing
GT -> Nothing
infix 5 <..<
(<..<) :: Ord x => x -> x -> Maybe (Interval x)
(<..<) x y =
case compare x y of
LT -> Just $ Interval (Limit Out x, Limit Out y)
EQ -> Nothing
GT -> Nothing
data Position
= Away
| Adjacent
| Overlap
| Prefix
| Suffixed
| Include
| Equal
deriving (Eq, Show)
position :: Ord x => Interval x -> Interval x -> (Position, Ordering)
position (Interval (il, ih)) (Interval (jl, jh)) =
case compare (LL il) (LL jl) of
LT -> (, LT) $
case compare_without_adherence ih jl of
LT -> Away
EQ ->
case (adherence ih, adherence jl) of
(In , In) -> Overlap
(Out, Out) -> Away
_ -> Adjacent
GT ->
case compare (HH ih) (HH jh) of
LT -> Overlap
EQ -> Suffixed
GT -> Include
EQ ->
case compare (HH ih) (HH jh) of
LT -> (Prefix, LT)
EQ -> (Equal , EQ)
GT -> (Prefix, GT)
GT -> (, GT) $
case compare_without_adherence il jh of
LT ->
case compare (HH ih) (HH jh) of
LT -> Include
EQ -> Suffixed
GT -> Overlap
EQ ->
case (adherence il, adherence jh) of
(In , In) -> Overlap
(Out, Out) -> Away
_ -> Adjacent
GT -> Away
infix 4 ..<<..
(..<<..) :: Ord x => Interval x -> Interval x -> Bool
(..<<..) i j = case position i j of
(Away, LT) -> True
_ -> False
infix 4 ..>>..
(..>>..) :: Ord x => Interval x -> Interval x -> Bool
(..>>..) i j = case position i j of
(Away, GT) -> True
_ -> False
infix 4 ..<..
(..<..) :: Ord x => Interval x -> Interval x -> Bool
(..<..) i j = case position i j of
(Away , LT) -> True
(Adjacent, LT) -> True
_ -> False
infix 4 ..>..
(..>..) :: Ord x => Interval x -> Interval x -> Bool
(..>..) i j = case position i j of
(Away , GT) -> True
(Adjacent, GT) -> True
_ -> False
infix 4 ..<=..
(..<=..) :: Ord x => Interval x -> Interval x -> Bool
(..<=..) i j = case position i j of
(Away , LT) -> True
(Adjacent, LT) -> True
(Overlap , LT) -> True
(Prefix , LT) -> True
(Suffixed, LT) -> True
(Include , GT) -> True
(Equal , _ ) -> True
_ -> False
infix 4 ..>=..
(..>=..) :: Ord x => Interval x -> Interval x -> Bool
(..>=..) i j = case position i j of
(Away , GT) -> True
(Adjacent, GT) -> True
(Overlap , GT) -> True
(Prefix , GT) -> True
(Suffixed, GT) -> True
(Include , LT) -> True
(Equal , _ ) -> True
_ -> False
union :: Ord x => Interval x -> Interval x -> Maybe (Interval x)
union i j =
case position i j of
(Away, _) ->
Nothing
(Adjacent, o) ->
case o of
LT -> Just $ Interval (low i, high j)
EQ -> Nothing
GT -> Just $ Interval (low j, high i)
(Overlap, o) ->
case o of
LT -> Just $ Interval (low i, high j)
EQ -> Nothing
GT -> Just $ Interval (low j, high i)
(Prefix, o) ->
case o of
LT -> Just j
EQ -> Nothing
GT -> Just i
(Suffixed, o) ->
case o of
LT -> Just i
EQ -> Nothing
GT -> Just j
(Include, o) ->
case o of
LT -> Just i
EQ -> Nothing
GT -> Just j
(Equal, _) ->
Just i
intersection :: Ord x => Interval x -> Interval x -> Maybe (Interval x)
intersection i j =
case position i j of
(Away, _) ->
Nothing
(Adjacent, _) ->
Nothing
(Overlap, o) ->
case o of
LT -> Just $ Interval (low j, high i)
EQ -> Nothing
GT -> Just $ Interval (low i, high j)
(Prefix, o) ->
case o of
LT -> Just i
EQ -> Nothing
GT -> Just j
(Suffixed, o) ->
case o of
LT -> Just j
EQ -> Nothing
GT -> Just i
(Include, o) ->
case o of
LT -> Just j
EQ -> Nothing
GT -> Just i
(Equal, _) ->
Just i
span :: Ord x => Interval x -> Interval x -> Interval x
span i j =
Interval
( unLL (min (LL $ low i) (LL $ low j))
, unHH (max (HH $ high i) (HH $ high j))
)
data Unlimitable x
= Unlimited_low
| Limited { limited :: x }
| Unlimited_high
deriving (Eq, Ord, Show)
instance Functor Unlimitable where
fmap _f Unlimited_low = Unlimited_low
fmap _f Unlimited_high = Unlimited_high
fmap f (Limited x) = Limited (f x)
instance Bounded (Unlimitable x) where
minBound = Unlimited_low
maxBound = Unlimited_high
instance Bounded (Limit (Unlimitable x)) where
minBound = Limit In Unlimited_low
maxBound = Limit In Unlimited_high
unlimited :: Ord x => Interval (Unlimitable x)
unlimited = Interval ( Limit In Unlimited_low
, Limit In Unlimited_high )
unlimit :: Ord x => Interval x -> Interval (Unlimitable x)
unlimit = fmap_unsafe Limited
(<..) :: Ord x => x -> Interval (Unlimitable x)
(<..) x = Interval (Limit Out (Limited x), Limit In Unlimited_high)
(<=..) :: Ord x => x -> Interval (Unlimitable x)
(<=..) x = Interval (Limit In (Limited x), Limit In Unlimited_high)
(..<) :: Ord x => x -> Interval (Unlimitable x)
(..<) x = Interval (Limit In Unlimited_low, Limit Out (Limited x))
(..<=) :: Ord x => x -> Interval (Unlimitable x)
(..<=) x = Interval (Limit In Unlimited_low, Limit In (Limited x))
newtype Pretty x = Pretty x
deriving (Eq, Ord)
instance (Ord x, Show x) => Show (Pretty (Interval x)) where
show (Pretty i) =
concat
[ case adherence (low i) of
In -> "["
Out -> "]"
, show (limit $ low i)
, ".."
, show (limit $ high i)
, case adherence (high i) of
In -> "]"
Out -> "["
]
instance (Ord x, Show x) => Show (Pretty (Unlimitable x)) where
show (Pretty x) =
case x of
Unlimited_low -> "-oo"
Limited l -> show l
Unlimited_high -> "+oo"