connections-0.0.3: src/Data/Semigroup/Join.hs
{-# 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.Join where
import Control.Applicative
import Data.Bool
import Data.Maybe
import Data.Either
import Data.Prd
import Data.Semigroup
import Data.Semigroup.Additive
import Data.Semigroup.Meet
import GHC.Generics (Generic)
import Numeric.Natural
import Data.Word
import Data.Int
import Data.Fixed
import Prelude ( Eq(..), Ord(..), Show, Ordering(..), Applicative(..), Functor(..), Monoid(..), Semigroup(..), (.), ($), (<$>), Integer)
import qualified Prelude as P
import qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Data.IntMap as IntMap
import qualified Data.IntSet as IntSet
infixr 5 ∨
-- | Join operation on a semilattice.
--
-- >>> (> (0::Int)) ∧ ((< 10) ∨ (== 15)) $ 10
-- False
--
-- >>> IntSet.fromList [1..5] ∧ IntSet.fromList [2..5]
-- fromList [2,3,4,5]
(∨) :: (Join-Semigroup) a => a -> a -> a
a ∨ b = unJoin (Join a <> Join b)
{-# INLINE (∨) #-}
bottom :: (Join-Monoid) a => a
bottom = unJoin mempty
{-# INLINE bottom #-}
type JoinSemilattice a = (Prd a, (Join-Semigroup) a)
-- | The partial ordering induced by the join-semilattice structure.
--
--
-- Normally when /a/ implements 'Prd' we should have:
-- @ 'joinLeq' x y ≡ x '<=' y @
--
joinLeq :: Eq a => (Join-Semigroup) a => a -> a -> Bool
joinLeq x y = x ∨ y == y
-- | The partial ordering induced by the join-semilattice structure.
--
-- Normally when /a/ implements 'Prd' we should have:
-- @ 'joinGeq' x y ≡ x '>=' y @
--
joinGeq :: Eq a => (Join-Semigroup) a => a -> a -> Bool
joinGeq x y = x ∨ y == x
-- | Partial version of 'Data.Ord.compare'.
--
-- Normally when /a/ implements 'Prd' we should have:
-- @ 'pcompareJoin' x y ≡ 'pcompare' x y @
--
pcompareJoin :: Eq a => (Join-Semigroup) a => a -> a -> Maybe Ordering
pcompareJoin x y
| x == y = Just EQ
| x ∨ y == y && x /= y = Just LT
| x ∨ y == x && x /= y = Just GT
| otherwise = Nothing
-- | A commutative 'Semigroup' under '∨'.
newtype Join a = Join { unJoin :: a } deriving (Eq, Generic, Ord, Show, Functor)
instance Applicative Join where
pure = Join
Join f <*> Join a = Join (f a)
-- >>> Down True ∨ Down False
-- Down False
instance (Meet-Semigroup) a => Semigroup (Join (Down a)) where
(<>) = liftA2 . liftA2 $ (∧)
-- >>> bottom :: Down Bool
-- Down True
instance (Meet-Monoid) a => Monoid (Join (Down a)) where
mempty = pure . pure $ top
-- >>> Down True ∧ Down False
-- Down True
instance (Join-Semigroup) a => Semigroup (Meet (Down a)) where
(<>) = liftA2 . liftA2 $ (∨)
-- >>> top :: Down Bool
-- Down False
instance (Join-Monoid) a => Monoid (Meet (Down a)) where
mempty = pure . pure $ bottom
instance Semigroup (Max a) => Semigroup (Join (Max a)) where
(<>) = liftA2 (<>)
instance (Join-Semigroup) (Max a) => Semigroup (Additive (Max a)) where
(<>) = liftA2 (∨)
instance (Join-Monoid) (Max a) => Monoid (Additive (Max a)) where
mempty = pure bottom
-- workaround for poorly specified entailment: instance (Ord a, Bounded a) => Monoid (Max a)
instance (Minimal a, Semigroup (Max a)) => Monoid (Join (Max a)) where
mempty = pure $ Max minimal
---------------------------------------------------------------------
-- Idempotent and selective instances
---------------------------------------------------------------------
{-
instance Ord a => Semigroup (Join (Down a)) where
(<>) = liftA2 . liftA2 $ (∨)
instance (Join-Monoid) a => Monoid (Join (Down a)) where
mempty = pure . pure $ bottom
-}
{-
instance (Join-Semigroup) a => Semigroup (Join (Dual a)) where
(<>) = liftA2 . liftA2 $ flip (∨)
instance (Join-Monoid) a => Monoid (Join (Dual a)) where
mempty = pure . pure $ bottom
instance (Join-Semigroup) a => Semigroup (Join (Down a)) where
(<>) = liftA2 . liftA2 $ (∨)
instance (Join-Monoid) a => Monoid (Join (Down a)) where
--Join (Down a) <> Join (Down b)
mempty = pure . pure $ bottom
instance Semigroup (Max a) => Semigroup (Join (Max a)) where
(<>) = liftA2 (<>)
-- MinPlus Predioid
-- >>> Min 1 `mul` Min 2 :: Min Int
-- Min {getMin = 3}
instance (Join-Semigroup) a => Semigroup (Multiplicative (Min a)) where
Multiplicative a <> Multiplicative b = Multiplicative $ liftA2 (∨) a b
-- MinPlus Dioid
instance (Join-Monoid) a => Monoid (Multiplicative (Min a)) where
mempty = Multiplicative $ pure bottom
-}
--instance ((Join-Semigroup) a, Minimal a) => Monoid (Join a) where
-- mempty = Join minimal
-- instance (Meet-Monoid) (Down a) => Monoid (Meet (Down a)) where mempty = Down <$> mempty
instance ((Join-Semigroup) a, (Join-Semigroup) b) => Semigroup (Join (a, b)) where
Join (x1, y1) <> Join (x2, y2) = Join (x1 ∨ x2, y1 ∨ y2)
instance (Join-Semigroup) a => Semigroup (Join (Maybe a)) where
Join (Just x) <> Join (Just y) = Join . Just $ x ∨ y
Join (x@Just{}) <> _ = Join x
Join Nothing <> y = y
instance (Join-Semigroup) a => Monoid (Join (Maybe a)) where
mempty = Join Nothing
instance ((Join-Semigroup) a, (Join-Semigroup) b) => Semigroup (Join (Either a b)) where
Join (Right x) <> Join (Right y) = Join . Right $ x ∨ y
Join(x@Right{}) <> _ = Join x
Join (Left x) <> Join (Left y) = Join . Left $ x ∨ y
Join (Left _) <> y = y
instance Ord a => Semigroup (Join (Set.Set a)) where
(<>) = liftA2 Set.union
instance (Ord k, (Join-Semigroup) a) => Semigroup (Join (Map.Map k a)) where
(<>) = liftA2 (Map.unionWith (∨))
instance (Join-Semigroup) a => Semigroup (Join (IntMap.IntMap a)) where
(<>) = liftA2 (IntMap.unionWith (∨))
instance Semigroup (Join IntSet.IntSet) where
(<>) = liftA2 IntSet.union
instance Monoid (Join IntSet.IntSet) where
mempty = Join IntSet.empty
instance (Join-Semigroup) a => Monoid (Join (IntMap.IntMap a)) where
mempty = Join IntMap.empty
instance Ord a => Monoid (Join (Set.Set a)) where
mempty = Join Set.empty
instance (Ord k, (Join-Semigroup) a) => Monoid (Join (Map.Map k a)) where
mempty = Join Map.empty
#define deriveJoinSemigroup(ty) \
instance Semigroup (Join ty) where { \
a <> b = (P.max) <$> a <*> b \
; {-# INLINE (<>) #-} \
}
deriveJoinSemigroup(())
deriveJoinSemigroup(Bool)
deriveJoinSemigroup(Int)
deriveJoinSemigroup(Int8)
deriveJoinSemigroup(Int16)
deriveJoinSemigroup(Int32)
deriveJoinSemigroup(Int64)
deriveJoinSemigroup(Integer)
deriveJoinSemigroup(Word)
deriveJoinSemigroup(Word8)
deriveJoinSemigroup(Word16)
deriveJoinSemigroup(Word32)
deriveJoinSemigroup(Word64)
deriveJoinSemigroup(Natural)
deriveJoinSemigroup(Uni)
deriveJoinSemigroup(Deci)
deriveJoinSemigroup(Centi)
deriveJoinSemigroup(Milli)
deriveJoinSemigroup(Micro)
deriveJoinSemigroup(Nano)
deriveJoinSemigroup(Pico)
#define deriveJoinMonoid(ty) \
instance Monoid (Join ty) where { \
mempty = pure minimal \
; {-# INLINE mempty #-} \
}
deriveJoinMonoid(())
deriveJoinMonoid(Bool)
deriveJoinMonoid(Int)
deriveJoinMonoid(Int8)
deriveJoinMonoid(Int16)
deriveJoinMonoid(Int32)
deriveJoinMonoid(Int64)
deriveJoinMonoid(Word)
deriveJoinMonoid(Word8)
deriveJoinMonoid(Word16)
deriveJoinMonoid(Word32)
deriveJoinMonoid(Word64)
deriveJoinMonoid(Natural)