content: {-# LANGUAGE DefaultSignatures #-}
  {-# LANGUAGE KindSignatures #-}
  
  {-|
  Module      : Data.JoinSemilattice.Class.Abs
  Description : Relationships between values and their absolutes.
  Copyright   : (c) Tom Harding, 2020
  License     : MIT
  -}
  module Data.JoinSemilattice.Class.Abs where
  
  import Data.Hashable (Hashable)
  import Data.JoinSemilattice.Class.Merge (Merge)
  import Data.JoinSemilattice.Defined (Defined)
  import Data.JoinSemilattice.Intersect (Intersect)
  import qualified Data.JoinSemilattice.Intersect as Intersect
  import Data.Kind (Type)
  
  -- | Unlike the 'abs' we know, which is a /function/ from a value to its
  -- absolute value, 'absR' is a /relationship/ between a value and its absolute.
  --
  -- For some types, while we can't truly reverse the `abs` function, we can say
  -- that there are two /possible/ inputs to consider, and so we can push /some/
  -- information in the reverse direction.
  class Merge x => AbsR (x :: Type) where
  
    -- | Given a value and its absolute, try to learn something in either
    -- direction.
    absR :: ( x, x ) -> ( x, x )
  
    -- | By default, this relationship is one-way.
    default absR :: Num x => ( x, x ) -> ( x, x )
    absR ( x, _ ) = ( mempty, abs x )
  
  instance (Eq x, Num x) => AbsR (Defined x)
  
  instance (Bounded x, Enum x, Ord x, Hashable x, Num x)
      => AbsR (Intersect x) where
    absR ( x, y ) = ( Intersect.union y (negate y), abs x )
  