{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE Safe #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Algebra.Lattice.Wide (
Wide(..)
) where
import Prelude ()
import Prelude.Compat
import Algebra.Lattice
import Algebra.PartialOrd
import Control.DeepSeq (NFData (..))
import Control.Monad (ap)
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 Wide a
= Top
| Middle a
| Bottom
deriving ( Eq, Ord, Show, Read, Data, Typeable, Generic, Functor, Foldable, Traversable
, Generic1
)
instance Applicative Wide where
pure = return
(<*>) = ap
instance Monad Wide where
return = Middle
Top >>= _ = Top
Bottom >>= _ = Bottom
Middle x >>= f = f x
instance NFData a => NFData (Wide a) where
rnf Top = ()
rnf Bottom = ()
rnf (Middle a) = rnf a
instance Hashable a => Hashable (Wide a)
instance Eq a => Lattice (Wide a) where
Top \/ _ = Top
Bottom \/ x = x
Middle _ \/ Top = Top
Middle x \/ Bottom = Middle x
Middle x \/ Middle y = if x == y then Middle x else Top
Bottom /\ _ = Bottom
Top /\ x = x
Middle _ /\ Bottom = Bottom
Middle x /\ Top = Middle x
Middle x /\ Middle y = if x == y then Middle x else Bottom
instance Eq a => BoundedJoinSemiLattice (Wide a) where
bottom = Bottom
instance Eq a => BoundedMeetSemiLattice (Wide a) where
top = Top
instance Eq a => PartialOrd (Wide a) where
leq Bottom _ = True
leq Top Bottom = False
leq Top (Middle _) = False
leq Top Top = True
leq (Middle _) Bottom = False
leq (Middle _) Top = True
leq (Middle x) (Middle y) = x == y
comparable Bottom _ = True
comparable Top _ = True
comparable (Middle _) Bottom = True
comparable (Middle _) Top = True
comparable (Middle x) (Middle y) = x == y
instance Universe a => Universe (Wide a) where
universe = Top : Bottom : map Middle universe
instance Finite a => Finite (Wide a) where
universeF = Top : Bottom : map Middle universeF
cardinality = fmap (2 +) (retag (cardinality :: Tagged a Natural))
instance QC.Arbitrary a => QC.Arbitrary (Wide a) where
arbitrary = QC.frequency
[ (1, pure Top)
, (1, pure Bottom)
, (9, Middle <$> QC.arbitrary)
]
shrink Top = []
shrink Bottom = []
shrink (Middle x) = Top : Bottom : map Middle (QC.shrink x)
instance QC.CoArbitrary a => QC.CoArbitrary (Wide a) where
coarbitrary Top = QC.variant (0 :: Int)
coarbitrary Bottom = QC.variant (0 :: Int)
coarbitrary (Middle x) = QC.variant (0 :: Int) . QC.coarbitrary x
instance QC.Function a => QC.Function (Wide a) where
function = QC.functionMap fromWide toWide where
fromWide Top = Left True
fromWide Bottom = Left False
fromWide (Middle x) = Right x
toWide (Left True) = Top
toWide (Left False) = Bottom
toWide (Right x) = Middle x