{-# LANGUAGE CPP #-} {-# LANGUAGE Safe #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DefaultSignatures #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE TypeFamilies #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Data.Semigroup.Meet ( type (-) , module Data.Semigroup.Meet ) where import Control.Applicative import Data.Bool import Data.Either import Data.Fixed import Data.Int import Data.Maybe import Data.Prd import Data.Ratio import Data.Semigroup import Data.Semigroup.Additive import Data.Semigroup.Multiplicative import Data.Word import GHC.Generics (Generic) import Numeric.Natural import Prelude ( Eq(..), Ord, Show, Ordering(..), Applicative(..), Functor(..) , Monoid(..), Semigroup(..), (.), ($), (<$>), Integer) import qualified Data.IntMap as IntMap import qualified Data.IntSet as IntSet import qualified Data.Map as Map import qualified Data.Set as Set import qualified Prelude as P infixr 6 ∧ -- | Meet operation on a semilattice. -- -- >>> (> (0::Int)) ∧ ((< 10) ∨ (== 15)) $ 15 -- True -- (∧) :: (Meet-Semigroup) a => a -> a -> a a ∧ b = unMeet (Meet a <> Meet b) {-# INLINE (∧) #-} top :: (Meet-Monoid) a => a top = unMeet mempty {-# INLINE top #-} -- | The partial ordering induced by the meet-semilattice structure. -- -- Normally when /a/ implements 'Prd' we should have: -- @ 'meetLeq' x y ≡ x '<=' y @ -- meetLeq :: Eq a => (Meet-Semigroup) a => a -> a -> Bool meetLeq x y = x ∧ y == x -- | The partial ordering induced by the meet-semilattice structure. -- -- Normally when /a/ implements 'Prd' we should have: -- @ 'meetGeq' x y ≡ x '>=' y @ -- meetGeq :: Eq a => (Meet-Semigroup) a => a -> a -> Bool meetGeq x y = x ∧ y == y -- | Partial version of 'Data.Ord.compare'. -- -- Normally when /a/ implements 'Prd' we should have: -- @ 'pcompareJoin' x y ≡ 'pcompare' x y @ -- pcompareMeet :: Eq a => (Meet-Semigroup) a => a -> a -> Maybe Ordering pcompareMeet x y | x == y = Just EQ | x ∧ y == x && x /= y = Just LT | x ∧ y == y && x /= y = Just GT | otherwise = Nothing type MeetSemilattice a = (Prd a, (Meet-Semigroup) a) newtype Meet a = Meet { unMeet :: a } deriving (Eq, Generic, Ord, Show, Functor) instance Applicative Meet where pure = Meet Meet f <*> Meet a = Meet (f a) -- >>> Min 1 ∧ Min 2 :: Min Int -- Min {getMin = 1} instance Semigroup (Min a) => Semigroup (Meet (Min a)) where (<>) = liftA2 (<>) instance (Meet-Semigroup) (Min a) => Semigroup (Additive (Min a)) where (<>) = liftA2 (∧) instance (Meet-Monoid) (Min a) => Monoid (Additive (Min a)) where mempty = pure top -- workaround for poorly specified entailment: instance (Ord a, Bounded a) => Monoid (Min a) -- >>> zero :: Min Natural -- Min {getMin = 0} instance (Maximal a, Semigroup (Min a)) => Monoid (Meet (Min a)) where mempty = pure $ Min maximal --------------------------------------------------------------------- -- Semigroup Instances --------------------------------------------------------------------- --instance ((Meet-Semigroup) a, Maximal a) => Monoid (Meet a) where -- mempty = Meet maximal -- MaxTimes Predioid instance (Meet-Semigroup) a => Semigroup (Meet (Max a)) where Meet a <> Meet b = Meet $ liftA2 (∧) a b -- MaxTimes Dioid instance (Meet-Monoid) a => Monoid (Meet (Max a)) where mempty = Meet $ pure top instance ((Meet-Semigroup) a, (Meet-Semigroup) b) => Semigroup (Meet (a, b)) where Meet (x1, y1) <> Meet (x2, y2) = Meet (x1 ∧ x2, y1 ∧ y2) instance (Meet-Semigroup) b => Semigroup (Meet (a -> b)) where (<>) = liftA2 . liftA2 $ (∧) {-# INLINE (<>) #-} instance (Meet-Monoid) b => Monoid (Meet (a -> b)) where mempty = pure . pure $ top instance (Meet-Semigroup) a => Semigroup (Meet (Maybe a)) where Meet Nothing <> _ = Meet Nothing Meet (Just{}) <> Meet Nothing = Meet Nothing Meet (Just x) <> Meet (Just y) = Meet . Just $ x ∧ y -- Mul a <> Mul b = Mul $ liftA2 (∧) a b instance (Meet-Monoid) a => Monoid (Meet (Maybe a)) where mempty = Meet $ pure top instance ((Meet-Semigroup) a, (Meet-Semigroup) b) => Semigroup (Meet (Either a b)) where Meet (Right x) <> Meet (Right y) = Meet . Right $ x ∧ y Meet (Right{}) <> y = y Meet (Left x) <> Meet (Left y) = Meet . Left $ x ∧ y Meet (x@Left{}) <> _ = Meet x instance Ord a => Semigroup (Meet (Set.Set a)) where (<>) = liftA2 Set.intersection instance (Ord k, (Meet-Semigroup) a) => Semigroup (Meet (Map.Map k a)) where (<>) = liftA2 (Map.intersectionWith (∧)) instance (Meet-Semigroup) a => Semigroup (Meet (IntMap.IntMap a)) where (<>) = liftA2 (IntMap.intersectionWith (∧)) instance Semigroup (Meet IntSet.IntSet) where (<>) = liftA2 IntSet.intersection {- instance (Ord k, (Meet-Monoid) k, (Meet-Monoid) a) => Monoid (Meet (Map.Map k a)) where mempty = Meet $ Map.singleton top top instance (Meet-Monoid) a => Monoid (Meet (IntMap.IntMap a)) where mempty = Meet $ IntMap.singleton 0 top --TODO check -} {- instance Monoid a => Semiring (Seq.Seq a) where (*) = liftA2 (<>) {-# INLINE (*) #-} fromBoolean = fromBooleanDef $ Seq.singleton mempty instance (Ord k, Monoid k, Monoid a) => Semiring (Map.Map k a) where xs * ys = foldMap (flip Map.map xs . (<>)) ys {-# INLINE (*) #-} fromBoolean = fromBooleanDef $ Map.singleton mempty mempty instance Monoid a => Semiring (IntMap.IntMap a) where xs * ys = foldMap (flip IntMap.map xs . (<>)) ys {-# INLINE (*) #-} fromBoolean = fromBooleanDef $ IntMap.singleton 0 mempty -} {- instance Semigroup (Meet ()) where _ <> _ = pure () {-# INLINE (<>) #-} instance Monoid (Meet ()) where mempty = pure () {-# INLINE mempty #-} instance Semigroup (Meet Bool) where a <> b = (P.&&) <$> a <*> b {-# INLINE (<>) #-} instance Monoid (Meet Bool) where mempty = pure True {-# INLINE mempty #-} -} #define deriveMeetSemigroup(ty) \ instance Semigroup (Meet ty) where { \ a <> b = (P.min) <$> a <*> b \ ; {-# INLINE (<>) #-} \ } deriveMeetSemigroup(()) deriveMeetSemigroup(Bool) deriveMeetSemigroup(Int) deriveMeetSemigroup(Int8) deriveMeetSemigroup(Int16) deriveMeetSemigroup(Int32) deriveMeetSemigroup(Int64) deriveMeetSemigroup(Integer) deriveMeetSemigroup(Word) deriveMeetSemigroup(Word8) deriveMeetSemigroup(Word16) deriveMeetSemigroup(Word32) deriveMeetSemigroup(Word64) deriveMeetSemigroup(Natural) deriveMeetSemigroup(Uni) deriveMeetSemigroup(Deci) deriveMeetSemigroup(Centi) deriveMeetSemigroup(Milli) deriveMeetSemigroup(Micro) deriveMeetSemigroup(Nano) deriveMeetSemigroup(Pico) deriveMeetSemigroup(Rational) deriveMeetSemigroup((Ratio Natural)) #define deriveMeetMonoid(ty) \ instance Monoid (Meet ty) where { \ mempty = pure maximal \ ; {-# INLINE mempty #-} \ } deriveMeetMonoid(()) deriveMeetMonoid(Bool) deriveMeetMonoid(Int) deriveMeetMonoid(Int8) deriveMeetMonoid(Int16) deriveMeetMonoid(Int32) deriveMeetMonoid(Int64) deriveMeetMonoid(Word) deriveMeetMonoid(Word8) deriveMeetMonoid(Word16) deriveMeetMonoid(Word32) deriveMeetMonoid(Word64)