{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE Safe #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
module Algebra.Lattice.Lexicographic (
Lexicographic(..)
) where
import Prelude ()
import Prelude.Compat
import Algebra.Lattice
import Algebra.PartialOrd
import Control.DeepSeq (NFData (..))
import Control.Monad (ap, liftM2)
import Data.Data (Data, Typeable)
import Data.Hashable (Hashable (..))
import Data.Universe.Class (Finite (..), Universe (..))
import Data.Universe.Helpers (Natural, Tagged, retag)
import GHC.Generics (Generic, Generic1)
import qualified Test.QuickCheck as QC
data Lexicographic k v = Lexicographic !k !v
deriving ( Eq, Ord, Show, Read, Data, Typeable, Generic, Functor, Foldable, Traversable
, Generic1
)
instance BoundedJoinSemiLattice k => Applicative (Lexicographic k) where
pure = return
(<*>) = ap
instance BoundedJoinSemiLattice k => Monad (Lexicographic k) where
return = Lexicographic bottom
Lexicographic k v >>= f =
case f v of
Lexicographic k' v' -> Lexicographic (k \/ k') v'
instance (NFData k, NFData v) => NFData (Lexicographic k v) where
rnf (Lexicographic k v) = rnf k `seq` rnf v
instance (Hashable k, Hashable v) => Hashable (Lexicographic k v)
instance (PartialOrd k, Lattice k, BoundedJoinSemiLattice v, BoundedMeetSemiLattice v) => Lattice (Lexicographic k v) where
l@(Lexicographic k1 v1) \/ r@(Lexicographic k2 v2)
| k1 == k2 = Lexicographic k1 (v1 \/ v2)
| k1 `leq` k2 = r
| k2 `leq` k1 = l
| otherwise = Lexicographic (k1 \/ k2) bottom
l@(Lexicographic k1 v1) /\ r@(Lexicographic k2 v2)
| k1 == k2 = Lexicographic k1 (v1 /\ v2)
| k1 `leq` k2 = l
| k2 `leq` k1 = r
| otherwise = Lexicographic (k1 /\ k2) top
instance (PartialOrd k, BoundedJoinSemiLattice k, BoundedJoinSemiLattice v, BoundedMeetSemiLattice v) => BoundedJoinSemiLattice (Lexicographic k v) where
bottom = Lexicographic bottom bottom
instance (PartialOrd k, BoundedMeetSemiLattice k, BoundedJoinSemiLattice v, BoundedMeetSemiLattice v) => BoundedMeetSemiLattice (Lexicographic k v) where
top = Lexicographic top top
instance (PartialOrd k, PartialOrd v) => PartialOrd (Lexicographic k v) where
Lexicographic k1 v1 `leq` Lexicographic k2 v2
| k1 == k2 = v1 `leq` v2
| k1 `leq` k2 = True
| otherwise = False
comparable (Lexicographic k1 v1) (Lexicographic k2 v2)
| k1 == k2 = comparable v1 v2
| otherwise = comparable k1 k2
instance (Universe k, Universe v) => Universe (Lexicographic k v) where
universe = map (uncurry Lexicographic) universe
instance (Finite k, Finite v) => Finite (Lexicographic k v) where
universeF = map (uncurry Lexicographic) universeF
cardinality = liftM2 (*)
(retag (cardinality :: Tagged k Natural))
(retag (cardinality :: Tagged v Natural))
instance (QC.Arbitrary k, QC.Arbitrary v) => QC.Arbitrary (Lexicographic k v) where
arbitrary = uncurry Lexicographic <$> QC.arbitrary
shrink (Lexicographic k v) = uncurry Lexicographic <$> QC.shrink (k, v)
instance (QC.CoArbitrary k, QC.CoArbitrary v) => QC.CoArbitrary (Lexicographic k v) where
coarbitrary (Lexicographic k v) = QC.coarbitrary (k, v)
instance (QC.Function k, QC.Function v) => QC.Function (Lexicographic k v) where
function = QC.functionMap (\(Lexicographic k v) -> (k,v)) (uncurry Lexicographic)