{-# Language TypeApplications #-} {-# Language AllowAmbiguousTypes #-} {-# Language ConstraintKinds #-} {-# Language DataKinds #-} {-# Language Safe #-} {-# Language ViewPatterns #-} {-# Language PatternSynonyms #-} {-# Language RankNTypes #-} {-# LANGUAGE DerivingVia #-} {-# LANGUAGE StandaloneDeriving #-} module Data.Connection.Class ( -- * Types Kan(..) , Conn() , Semilattice , Extremal , ConnFloat , ConnDouble , ConnInteger , ConnRational , ConnExtended -- * Connection L , ConnL , pattern ConnL , connL , swapL , embedL , ceiling , ceiling1 , ceiling2 , filterL , minimal , (\/) , glb -- * Connection R , ConnR , pattern ConnR , connR , swapR , floor , floor1 , floor2 , embedR , filterR , maximal , (/\) , lub -- * Connection k , Trip , pattern Conn , maybeL , maybeR , choice , strong , fmapped -- * Connection , Connection(..) , Triple ) where import safe Control.Applicative (liftA2) import safe Control.Category ((>>>)) import safe Data.Bool (bool) import safe Data.Connection.Conn import safe Data.Connection.Int import safe Data.Connection.Word import safe Data.Connection.Float import safe Data.Connection.Double import safe Data.Connection.Ratio import safe Data.Functor.Contravariant import safe Data.Functor.Identity import safe Data.Monoid import safe Data.Order import safe Data.Order.Extended import safe Data.Order.Interval import safe Data.Word import safe Data.Int import safe GHC.TypeNats import safe Numeric.Natural import safe Prelude hiding (Bounded, floor, ceiling, fromInteger, fromRational) import safe qualified Control.Category as C import safe qualified Data.IntMap as IntMap import safe qualified Data.IntSet as IntSet import safe qualified Data.Map as Map import safe qualified Data.Set as Set import safe qualified Data.Finite as F import safe qualified Data.Universe.Class as U import safe qualified Prelude as P -- $setup -- >>> :set -XTypeApplications -- >>> import Data.Int -- >>> import Prelude hiding (Ord(..), Bounded, fromInteger, fromRational, RealFrac(..)) -- >>> import qualified Prelude as P -- >>> :load Data.Connection -- | Semilattices. -- -- A complete is a partially ordered set in which every two elements have a unique join -- (least upper bound or supremum) and a unique meet (greatest lower bound or infimum). -- -- These operations may in turn be defined by the lower and upper adjoints to the unique -- function /a -> (a, a)/. -- -- /Associativity/ -- -- @ -- x '\/' (y '\/' z) = (x '\/' y) '\/' z -- x '/\' (y '/\' z) = (x '/\' y) '/\' z -- @ -- -- /Commutativity/ -- -- @ -- x '\/' y = y '\/' x -- x '/\' y = y '/\' x -- @ -- -- /Idempotency/ -- -- @ -- x '\/' x = x -- x '/\' x = x -- @ -- -- /Absorption/ -- -- @ -- (x '\/' y) '/\' y = y -- (x '/\' y) '\/' y = y -- @ -- -- See < https://en.wikipedia.org/wiki/Absorption_law Absorption >. -- -- Note that distributivity is _not_ a requirement for a complete. -- However when /a/ is distributive we have; -- -- @ -- 'glb' x y z = 'lub' x y z -- @ -- -- See < https://en.wikipedia.org/wiki/Lattice_(order) >. -- type Semilattice k a = Connection k (a, a) a type Extremal k = Connection k () type ConnInteger k = Connection k (Maybe Integer) type ConnFloat k = Connection k Float type ConnDouble k = Connection k Double type ConnRational k = Connection k Rational type ConnExtended k a b = Connection k a (Extended b) -- | An < https://ncatlab.org/nlab/show/adjoint+string adjoint string > of Galois connections of length 2 or 3. -- class (Preorder a, Preorder b) => Connection k a b where -- | -- -- >>> range (conn @_ @Double @Float) pi -- (3.1415925,3.1415927) -- >>> range (conn @_ @Rational @Float) (1 :% 7) -- (0.14285713,0.14285715) -- >>> range (conn @_ @Rational @Float) (1 :% 8) -- (0.125,0.125) -- conn :: Conn k a b -- | A constraint kind representing an of Galois connections. -- type Triple a b = (Connection 'L a b, Connection 'R a b) --------------------------------------------------------------------- -- Connection L --------------------------------------------------------------------- -- | A specialization of /conn/ to left-side connections. -- -- This is a convenience function provided primarily to avoid needing -- to enable /DataKinds/. -- connL :: Connection 'L a b => ConnL a b connL = conn @'L -- | Extract the center of a 'Trip' or upper half of a 'ConnL'. -- embedL :: Connection 'L a b => b -> a embedL = embed connL -- | Extract the ceiling of a 'Trip' or lower half of a 'ConnL'. -- -- > ceiling @a @a = id -- -- >>> ceiling @Rational @Float (0 :% 0) -- NaN -- >>> ceiling @Rational @Float (1 :% 0) -- Infinity -- >>> ceiling @Rational @Float (13 :% 10) -- 1.3000001 -- ceiling :: Connection 'L a b => a -> b ceiling = lowerL connL -- | Lift a unary function over a 'ConnL'. -- ceiling1 :: Connection 'L a b => (a -> a) -> b -> b ceiling1 = lowerL1 connL -- | Lift a binary function over a 'ConnL'. -- ceiling2 :: Connection 'L a b => (a -> a -> a) -> b -> b -> b ceiling2 = lowerL2 connL -- | Obtain the principal filter in /B/ generated by an element of /A/. -- -- A subset /B/ of a lattice is an filter if and only if it is an upper set -- that is closed under finite meets, i.e., it is nonempty and for all -- /x/, /y/ in /B/, the element @x /\ y@ is also in /b/. -- -- /filterL/ and /filterR/ commute with /Down/: -- -- > filterL a b <=> filterR (Down a) (Down b) -- -- > filterL (Down a) (Down b) <=> filterR a b -- -- /filterL a/ is upward-closed for all /a/: -- -- > a <= b1 && b1 <= b2 => a <= b2 -- -- > a1 <= b && inf a2 <= b => ceiling a1 /\ ceiling a2 <= b -- -- See -- filterL :: Connection 'L a b => a -> b -> Bool filterL a b = ceiling a <~ b -- | A minimal element of a preorder defined by a connection with '()'. -- -- 'minimal' needn't be unique, but we must have: -- -- > x <~ minimal => x ~~ minimal -- minimal :: Extremal 'L a => a minimal = lowerL connL () infixr 5 \/ -- | Semigroup operation on a join-semilattice. -- -- > (\/) = curry $ lowerL forked -- (\/) :: Semilattice 'L a => a -> a -> a (\/) = curry $ lowerL connL -- | Greatest lower bound operator. -- -- > glb x x y = x -- > glb x y z = glb z x y -- > glb x x y = x -- > glb x y z = glb x z y -- > glb (glb x w y) w z = glb x w (glb y w z) -- -- >>> glb 1.0 9.0 7.0 -- 7.0 -- >>> glb 1.0 9.0 (0.0 / 0.0) -- 9.0 -- >>> glb (fromList [1..3]) (fromList [3..5]) (fromList [5..7]) :: Set Int -- fromList [3,5] -- glb :: Triple (a, a) a => a -> a -> a -> a glb x y z = (x \/ y) /\ (y \/ z) /\ (z \/ x) --------------------------------------------------------------------- -- Connection R --------------------------------------------------------------------- -- | A specialization of /conn/ to right-side connections. -- -- This is a convenience function provided primarily to avoid needing -- to enable /DataKinds/. -- connR :: Connection 'R a b => ConnR a b connR = conn @'R -- | Extract the floor of a 'Trip' or upper half of a 'ConnL'. -- -- > floor @a @a = id -- -- >>> floor @Rational @Float (0 :% 0) -- NaN -- >>> floor @Rational @Float (1 :% 0) -- Infinity -- >>> floor @Rational @Float (13 :% 10) -- 1.3 -- floor :: Connection 'R a b => a -> b floor = upperR connR -- | Lift a unary function over a 'ConnR'. -- floor1 :: Connection 'R a b => (a -> a) -> b -> b floor1 = upperR1 connR -- | Lift a binary function over a 'ConnR'. -- floor2 :: Connection 'R a b => (a -> a -> a) -> b -> b -> b floor2 = upperR2 connR -- | Extract the center of a 'Trip' or lower half of a 'ConnR'. -- embedR :: Connection 'R a b => b -> a embedR = embed connR -- | Obtain the principal ideal in /B/ generated by an element of /A/. -- -- A subset /B/ of a lattice is an ideal if and only if it is a lower set -- that is closed under finite joins, i.e., it is nonempty and for all -- /x/, /y/ in /B/, the element /x \/ y/ is also in /B/. -- -- /filterR a/ is downward-closed for all /a/: -- -- > a >= b1 && b1 >= b2 => a >= b2 -- -- > a1 >= b && a2 >= b => floor a1 \/ floor a2 >= b -- -- See -- filterR :: Connection 'R a b => a -> b -> Bool filterR a b = b <~ floor a -- | A maximal element of a preorder defined by a connection with '()'. -- -- 'maximal' needn't be unique, but we must have: -- -- > x >~ maximal => x ~~ maximal -- maximal :: Extremal 'R a => a maximal = upperR connR () infixr 6 /\ -- comment for the parser -- | Semigroup operation on a meet-semilattice. -- -- > (/\) = curry $ upperR forked -- (/\) :: Semilattice 'R a => a -> a -> a (/\) = curry $ upperR connR -- | Least upper bound operator. -- -- The order dual of 'glb'. -- -- >>> lub 1.0 9.0 7.0 -- 7.0 -- >>> lub 1.0 9.0 (0.0 / 0.0) -- 1.0 -- lub :: Triple (a, a) a => a -> a -> a -> a lub x y z = (x /\ y) \/ (y /\ z) \/ (z /\ x) --------------------------------------------------------------------- -- Connection --------------------------------------------------------------------- maybeL :: Triple () b => Trip (Maybe a) (Either a b) maybeL = trip f g h where f = maybe (Right minimal) Left g = either Just (const Nothing) h = maybe (Right maximal) Left maybeR :: Triple () a => Trip (Maybe b) (Either a b) maybeR = trip f g h where f = maybe (Left minimal) Right g = either (const Nothing) Just h = maybe (Left maximal) Right --------------------------------------------------------------------- -- Instances --------------------------------------------------------------------- instance Preorder a => Connection k a a where conn = C.id instance Connection 'R Word16 Word8 where conn = swapR w08w16 instance Connection 'R Word32 Word8 where conn = swapR w08w32 instance Connection 'R Word32 Word16 where conn = swapR w16w32 instance Connection 'R Word64 Word8 where conn = swapR w08w64 instance Connection 'R Word64 Word16 where conn = swapR w16w64 instance Connection 'R Word64 Word32 where conn = swapR w32w64 instance Connection k Word Word64 where conn = wxxw64 instance Connection 'R Natural Word8 where conn = swapR w08nat instance Connection 'R Natural Word16 where conn = swapR w16nat instance Connection 'R Natural Word32 where conn = swapR w32nat instance Connection 'R Natural Word64 where conn = swapR w64nat instance Connection 'R Natural Word where conn = swapR wxxnat instance Connection 'R Natural Integer where conn = swapR intnat instance Connection 'R Int32 Int8 where conn = swapR i08i32 instance Connection 'R Int32 Int16 where conn = swapR i16i32 instance Connection 'R Int64 Int8 where conn = swapR i08i64 instance Connection 'R Int64 Int16 where conn = swapR i16i64 instance Connection 'R Int64 Int32 where conn = swapR i32i64 instance Connection k Int Int64 where conn = ixxi64 instance Connection 'R (Maybe Integer) Word8 where conn = swapR $ w08nat >>> natint instance Connection 'R (Maybe Integer) Word16 where conn = swapR $ w16nat >>> natint instance Connection 'R (Maybe Integer) Word32 where conn = swapR $ w32nat >>> natint instance Connection 'R (Maybe Integer) Word64 where conn = swapR $ w64nat >>> natint instance Connection 'R (Maybe Integer) Word where conn = swapR $ wxxnat >>> natint instance Connection 'R (Maybe Integer) Natural where conn = swapR natint instance Connection 'R (Maybe Integer) Int8 where conn = swapR i08int instance Connection 'R (Maybe Integer) Int16 where conn = swapR i16int instance Connection 'R (Maybe Integer) Int32 where conn = swapR i32int instance Connection 'R (Maybe Integer) Int64 where conn = swapR i64int instance Connection 'R (Maybe Integer) Int where conn = swapR ixxint instance Connection 'R (Maybe Integer) Integer where -- | Provided as a shim for /RebindableSyntax/. -- Note that this instance will clip negative numbers to zero. conn = swapR $ intnat >>> natint instance Connection k Int8 Word8 where conn = i08w08 instance Connection k Int16 Word16 where conn = i16w16 instance Connection k Int32 Word32 where conn = i32w32 instance Connection k Int64 Word64 where conn = i64w64 instance Connection k Int Word where conn = ixxwxx instance Connection k Double Float where conn = f64f32 instance Connection k Rational Float where conn = ratf32 instance Connection k Rational Double where conn = ratf64 instance Connection k Rational (Extended Int8) where conn = rati08 instance Connection k Rational (Extended Int16) where conn = rati16 instance Connection k Rational (Extended Int32) where conn = rati32 instance Connection k Rational (Extended Int64) where conn = rati64 instance Connection k Rational (Extended Int) where conn = ratixx instance Connection k Rational (Extended Integer) where conn = ratint instance Connection k Float (Extended Int8) where conn = f32i08 instance Connection k Float (Extended Int16) where conn = f32i16 instance Connection 'L Float (Extended Int32) where conn = conn >>> fmapped (i16w16 >>> w16w32 >>> w32i32) instance Connection 'L Float (Extended Int64) where conn = conn >>> fmapped (i16w16 >>> w16w64 >>> w64i64) instance Connection 'L Float (Extended Int) where conn = conn >>> fmapped (i16w16 >>> w16wxx >>> swapL ixxwxx) instance Connection k Double (Extended Int8) where conn = f64i08 instance Connection k Double (Extended Int16) where conn = f64i16 instance Connection k Double (Extended Int32) where conn = f64i32 instance Connection 'L Double (Extended Int64) where conn = conn >>> fmapped (i32w32 >>> w32w64 >>> w64i64) instance Connection 'L Double (Extended Int) where conn = conn >>> fmapped (i32w32 >>> w32wxx >>> swapL ixxwxx) instance Connection k a b => Connection k (Identity a) b where conn = Conn runIdentity Identity runIdentity >>> conn instance Connection k a b => Connection k a (Identity b) where conn = conn >>> Conn Identity runIdentity Identity --------------------------------------------------------------------- -- --------------------------------------------------------------------- fork :: a -> (a, a) fork x = (x, x) semilatticeN5 :: (Total a, Fractional a) => Conn k (a, a) a semilatticeN5 = Conn (uncurry joinN5) fork (uncurry meetN5) where joinN5 x y = maybe (1 / 0) (bool y x . (>= EQ)) (pcompare x y) meetN5 x y = maybe (-1 / 0) (bool y x . (<= EQ)) (pcompare x y) extremalN5 :: (Total a, Fractional a) => Conn k () a extremalN5 = Conn (const $ -1/0) (const ()) (const $ 1/0) semilatticeOrd :: (Total a) => Conn k (a, a) a semilatticeOrd = Conn (uncurry max) fork (uncurry min) extremalOrd :: (Total a, P.Bounded a) => Conn k () a extremalOrd = Conn (const minBound) (const ()) (const maxBound) instance Connection k ((),()) () where conn = semilatticeOrd instance Connection k (Bool, Bool) Bool where conn = semilatticeOrd instance Connection k () Bool where conn = extremalOrd instance Connection k (Ordering, Ordering) Ordering where conn = semilatticeOrd instance Connection k () Ordering where conn = extremalOrd instance Connection k (Word8, Word8) Word8 where conn = semilatticeOrd instance Connection k () Word8 where conn = extremalOrd instance Connection k (Word16, Word16) Word16 where conn = semilatticeOrd instance Connection k () Word16 where conn = extremalOrd instance Connection k (Word32, Word32) Word32 where conn = semilatticeOrd instance Connection k () Word32 where conn = extremalOrd instance Connection k (Word64, Word64) Word64 where conn = semilatticeOrd instance Connection k () Word64 where conn = extremalOrd instance Connection k (Word, Word) Word where conn = semilatticeOrd instance Connection k () Word where conn = extremalOrd instance Connection k (Natural, Natural) Natural where conn = semilatticeOrd instance Connection k (Positive, Positive) Positive where conn = semilatticeN5 instance Connection k () Positive where conn = Conn (const $ 0 :% 1) (const ()) (const $ 1 :% 0) instance Connection k (Int8, Int8) Int8 where conn = semilatticeOrd instance Connection k () Int8 where conn = extremalOrd instance Connection k (Int16, Int16) Int16 where conn = semilatticeOrd instance Connection k () Int16 where conn = extremalOrd instance Connection k (Int32, Int32) Int32 where conn = semilatticeOrd instance Connection k () Int32 where conn = extremalOrd instance Connection k (Int64, Int64) Int64 where conn = semilatticeOrd instance Connection k () Int64 where conn = extremalOrd instance Connection k (Int, Int) Int where conn = semilatticeOrd instance Connection k () Int where conn = extremalOrd instance Connection k (Integer, Integer) Integer where conn = semilatticeOrd instance Connection k (Rational, Rational) Rational where conn = semilatticeN5 instance Connection k () Rational where conn = Conn (const $ -1 :% 0) (const ()) (const $ 1 :% 0) instance Connection k (F.Finite n, F.Finite n) (F.Finite n) where conn = semilatticeOrd instance KnownNat n => Connection k () (F.Finite n) where conn = extremalOrd instance Connection k (Float, Float) Float where conn = semilatticeN5 instance Connection k () Float where conn = extremalN5 instance Connection k (Double, Double) Double where conn = semilatticeN5 instance Connection k () Double where conn = extremalN5 instance Total a => Connection k (Set.Set a, Set.Set a) (Set.Set a) where conn = Conn (uncurry Set.union) fork (uncurry Set.intersection) --instance (Total a, U.Finite a) => Connection k () (Set.Set a) where -- conn = Conn (const Set.empty) (const ()) (const $ Set.fromList U.universeF) instance (Total a) => Connection 'L () (Set.Set a) where conn = ConnL (const Set.empty) (const ()) instance (Total a, U.Finite a) => Connection 'R () (Set.Set a) where conn = ConnR (const ()) (const $ Set.fromList U.universeF) instance Connection k (IntSet.IntSet, IntSet.IntSet) IntSet.IntSet where conn = Conn (uncurry IntSet.union) fork (uncurry IntSet.intersection) instance Connection k () IntSet.IntSet where conn = Conn (const IntSet.empty) (const ()) (const $ IntSet.fromList U.universeF) instance (Total a, Connection 'L (b,b) b) => Connection 'L (Map.Map a b, Map.Map a b) (Map.Map a b) where conn = ConnL (uncurry $ Map.unionWith (\/)) fork instance (Total a, Connection 'R (b,b) b) => Connection 'R (Map.Map a b, Map.Map a b) (Map.Map a b) where conn = ConnR fork (uncurry $ Map.intersectionWith (/\)) instance (Total a, Preorder b) => Connection 'L () (Map.Map a b) where conn = ConnL (const Map.empty) (const ()) instance (Total a, U.Finite a, Connection 'R () b) => Connection 'R () (Map.Map a b) where conn = ConnR (const ()) (const . Map.fromList $ U.universeF `zip` repeat maximal) instance Connection 'L (a,a) a => Connection 'L (IntMap.IntMap a, IntMap.IntMap a) (IntMap.IntMap a) where conn = ConnL (uncurry $ IntMap.unionWith (\/)) fork instance Connection 'R (a,a) a => Connection 'R (IntMap.IntMap a, IntMap.IntMap a) (IntMap.IntMap a) where conn = ConnR fork (uncurry $ IntMap.intersectionWith (/\)) instance Preorder a => Connection 'L () (IntMap.IntMap a) where conn = ConnL (const IntMap.empty) (const ()) instance Connection 'R () a => Connection 'R () (IntMap.IntMap a) where conn = ConnR (const ()) (const . IntMap.fromList $ U.universeF `zip` repeat maximal) joinMaybe :: Connection 'L (a, a) a => Maybe a -> Maybe a -> Maybe a joinMaybe (Just x) (Just y) = Just (x \/ y) joinMaybe u@(Just _) _ = u joinMaybe _ u@(Just _) = u joinMaybe Nothing Nothing = Nothing meetMaybe :: Connection 'R (a, a) a => Maybe a -> Maybe a -> Maybe a meetMaybe Nothing Nothing = Nothing meetMaybe Nothing _ = Nothing meetMaybe _ Nothing = Nothing meetMaybe (Just x) (Just y) = Just (x /\ y) instance Connection 'L (a, a) a => Connection 'L (Maybe a, Maybe a) (Maybe a) where conn = ConnL (uncurry joinMaybe) fork instance Connection 'R (a, a) a => Connection 'R (Maybe a, Maybe a) (Maybe a) where conn = ConnR fork (uncurry meetMaybe) instance Preorder a => Connection 'L () (Maybe a) where conn = ConnL (const Nothing) (const ()) instance Connection 'R () a => Connection 'R () (Maybe a) where conn = ConnR (const ()) (const $ Just maximal) joinExtended :: Connection 'L (a, a) a => Extended a -> Extended a -> Extended a joinExtended Top _ = Top joinExtended _ Top = Top joinExtended (Extended x) (Extended y) = Extended (x \/ y) joinExtended Bottom y = y joinExtended x Bottom = x meetExtended :: Connection 'R (a, a) a => Extended a -> Extended a -> Extended a meetExtended Top y = y meetExtended x Top = x meetExtended (Extended x) (Extended y) = Extended (x /\ y) meetExtended Bottom _ = Bottom meetExtended _ Bottom = Bottom instance Connection 'L (a, a) a => Connection 'L (Extended a, Extended a) (Extended a) where conn = ConnL (uncurry joinExtended) fork instance Connection 'R (a, a) a => Connection 'R (Extended a, Extended a) (Extended a) where conn = ConnR fork (uncurry meetExtended) instance Preorder a => Connection k () (Extended a) where conn = Conn (const Bottom) (const ()) (const Top) joinEither :: (Connection 'L (a, a) a, Connection 'L (b, b) b) => Either a b -> Either a b -> Either a b joinEither (Right x) (Right y) = Right (x \/ y) joinEither u@(Right _) _ = u joinEither _ u@(Right _) = u joinEither (Left x) (Left y) = Left (x \/ y) meetEither :: (Connection 'R (a, a) a, Connection 'R (b, b) b) => Either a b -> Either a b -> Either a b meetEither (Left x) (Left y) = Left (x /\ y) meetEither l@(Left _) _ = l meetEither _ l@(Left _) = l meetEither (Right x) (Right y) = Right (x /\ y) -- | All minimal elements of the upper lattice cover all maximal elements of the lower lattice. instance (Connection 'L (a,a) a, Connection 'L (b,b) b) => Connection 'L (Either a b, Either a b) (Either a b) where conn = ConnL (uncurry joinEither) fork instance (Connection 'R (a,a) a, Connection 'R (b,b) b) => Connection 'R (Either a b, Either a b) (Either a b) where conn = ConnR fork (uncurry meetEither) instance (Connection 'L () a, Preorder b) => Connection 'L () (Either a b) where conn = ConnL (const $ Left minimal) (const ()) instance (Preorder a, Connection 'R () b) => Connection 'R () (Either a b) where conn = ConnR (const ()) (const $ Right maximal) joinTuple :: (Connection 'L (a, a) a, Connection 'L (b, b) b) => (a, b) -> (a, b) -> (a, b) joinTuple (x1, y1) (x2, y2) = (x1 \/ x2, y1 \/ y2) meetTuple :: (Connection 'R (a, a) a, Connection 'R (b, b) b) => (a, b) -> (a, b) -> (a, b) meetTuple (x1, y1) (x2, y2) = (x1 /\ x2, y1 /\ y2) instance (Triple (a, a) a, Triple (b, b) b) => Connection k ((a, b), (a, b)) (a, b) where conn = Conn (uncurry joinTuple) fork (uncurry meetTuple) instance (Triple () a, Triple () b) => Connection k () (a, b) where conn = Conn (const (minimal, minimal)) (const ()) (const (maximal, maximal)) instance (U.Finite a, Triple (b, b) b) => Connection k (a -> b, a -> b) (a -> b) where conn = Conn (uncurry $ liftA2 (\/)) fork (uncurry $ liftA2 (/\)) instance (U.Finite a, Triple () b) => Connection k () (a -> b) where conn = Conn (const $ pure minimal) (const ()) (const $ pure maximal) instance (U.Finite a, Triple (a, a) a) => Connection k (Endo a, Endo a) (Endo a) where conn = Conn (\(Endo x, Endo y) -> Endo $ x\/y) fork (\(Endo x, Endo y) -> Endo $ x/\y) instance (U.Finite a, Triple () a) => Connection k () (Endo a) where conn = Conn (const $ Endo minimal) (const ()) (const $ Endo maximal) instance (U.Finite a, Triple (b, b) b) => Connection k (Op b a, Op b a) (Op b a) where conn = Conn (\(Op x, Op y) -> Op $ x\/y) fork (\(Op x, Op y) -> Op $ x/\y) instance (U.Finite a, Triple () b) => Connection k () (Op b a) where conn = Conn (const $ Op minimal) (const ()) (const $ Op maximal) instance U.Finite a => Connection k (Predicate a, Predicate a) (Predicate a) where conn = Conn (\(Predicate x, Predicate y) -> Predicate $ x\/y) fork (\(Predicate x, Predicate y) -> Predicate $ x/\y) instance U.Finite a => Connection k () (Predicate a) where conn = Conn (const $ Predicate minimal) (const ()) (const $ Predicate maximal) {- instance (Applicative m, Connection k r) => Connection k (ContT r m a) where (<>) = liftA2 joinCont instance (Applicative m, Connection k () r) => Connection k () (ContT r m a) where mempty = pure . ContT . const $ pure bottom instance Monad m => Connection k (SelectT r m a) where (<>) = liftA2 joinSelect instance MonadPlus m => Connection k () (SelectT r m a)) where bottom = pure empty instance (Ord.Ord a, Preorder a, Preorder r, Finite r) => Preorder (Cont r a) where (ContT x) <~ (ContT y) = x `contLe` y instance (Ord.Ord a, Preorder a, Preorder r, Finite r) => Preorder (Select r a) where (SelectT x) <~ (SelectT y) = x `contLe` y instance (Applicative m, Total a, Preorder r, Finite r, Connection 'L r) => Connection 'L (ContT r m a, ContT r m a) (ContT r m a) where conn = ConnL (uncurry joinCont) fork joinCont :: (Applicative m, Connection 'L (r,r) r) => ContT r m a -> ContT r m a -> ContT r m a joinCont (ContT f) (ContT g) = ContT $ \p -> liftA2 join (f p) (g p) instance (Monad m, Total a, Preorder r, Finite r, Extremal 'L r) => Connection 'L (SelectT r m a, SelectT r m a) (SelectT r m a) where conn = ConnL (uncurry joinSelect) fork joinSelect :: (Monad m, Extremal 'L r) => SelectT r m b -> SelectT r m b -> SelectT r m b joinSelect x y = branch x y >>= id where ifM c x y = c >>= \b -> if b then x else y branch x y = SelectT $ \p -> ifM ((~~ maximal) <$> p x) (pure x) (pure y) -}