{-# LANGUAGE DataKinds #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE TypeFamilyDependencies #-} -- | This module provides a collection of types and type families. -- -- Specifically it defines the session type data type, capability data type and type families that compute using session types or capabilities as arguments. module Control.SessionTypes.Types ( -- * Session Types ST(..), Cap(..), GetST, GetCtx, -- * Duality Dual, DualST, MapDual, -- * Removing RemoveSend, RemoveSendST, MapRemoveSend, RemoveRecv, RemoveRecvST, MapRemoveRecv, -- * Applying Constraints HasConstraint, HasConstraintST, MapHasConstraint, HasConstraints, -- * Boolean functions IfThenElse, Not, Or, -- * Product type Prod (..), Left, Right, -- * Other Nat(..), Ref(..), TypeEqList, Append ) where import Data.Kind import Data.Typeable infixr 6 :?> infixr 6 :!> -- | The session type data type -- -- Each constructor denotes a specific session type. Using the `DataKinds` pragma the constructors are promoted to types and `ST` is promoted to a kind. data ST a = (:?>) a (ST a) -- ^ Send a value | (:!>) a (ST a) -- ^ Recv a value | Sel [ST a] -- ^ Selection of branches | Off [ST a] -- ^ Offering of branches | R (ST a) -- ^ Delimit the scope of recursion | Wk (ST a) -- ^ Weaken the scope of recursion | V -- ^ Recursion variable | Eps -- ^ End of the session deriving Typeable -- | A capability that stores a context/scope that is a list of session types and a session type data Cap a = Cap [ST a] (ST a) deriving Typeable -- | Retrieves the session type from the capability type family GetST s where GetST ('Cap ctx s) = s -- | Retrieves the context from the capability type family GetCtx s where GetCtx ('Cap ctx s) = ctx -- | Type family for calculating the dual of a session type. It may be applied to a capability. -- -- We made `Dual` injective to support calculating the dual of a selection that contains -- an ambiguous branch. Of course that does require that the dual of that ambiguous branch must be known. type family Dual s = r | r -> s where Dual ('Cap ctx s) = 'Cap (MapDual ctx) (DualST s) -- | Type family for calculating the dual of a session type. It may be applied to the actual session type. type family DualST (a :: ST c) = (b :: ST c) | b -> a where DualST (s :!> r) = s :?> DualST r DualST (s :?> r) = s :!> DualST r DualST (Sel xs) = Off (MapDual xs) DualST (Off xs) = Sel (MapDual xs) DualST (R s) = R (DualST s) DualST (Wk s) = Wk (DualST s) DualST V = V DualST Eps = Eps -- | Type family for calculating the dual of a list of session types. type family MapDual xs = ys | ys -> xs where MapDual '[] = '[] MapDual (s ': xs) = DualST s ': MapDual xs -- | Type family for removing the send session type from the given session type. It may be applied to a capability. type family RemoveSend s where RemoveSend ('Cap ctx s) = 'Cap (MapRemoveSend ctx) (RemoveSendST s) -- | Type family for removing the send session type from the given session type. It may be applied to a session type. type family RemoveSendST s where RemoveSendST (a :!> r) = RemoveSendST r RemoveSendST (a :?> r) = a :?> RemoveSendST r RemoveSendST (Sel xs) = Sel (MapRemoveSend xs) RemoveSendST (Off xs) = Off (MapRemoveSend xs) RemoveSendST (R s) = R (RemoveSendST s) RemoveSendST (Wk s) = Wk (RemoveSendST s) RemoveSendST s = s -- | Type family for removing the send session type from a list of session types. type family MapRemoveSend ctx where MapRemoveSend '[] = '[] MapRemoveSend (s ': ctx) = RemoveSendST s ': MapRemoveSend ctx -- | Type family for removing the receive session type from the given session type. It may be applied to a capability. type family RemoveRecv s where RemoveRecv ('Cap ctx s) = 'Cap (MapRemoveRecv ctx) (RemoveRecvST s) -- | Type family for removing the receive session type from the given session type. It may be applied to a session type. type family MapRemoveRecv ctx where MapRemoveRecv '[] = '[] MapRemoveRecv (s ': ctx) = RemoveRecvST s ': MapRemoveRecv ctx -- | Type family for removing the receive session type from a list of session types. type family RemoveRecvST s where RemoveRecvST (a :!> r) = a :!> RemoveRecvST r RemoveRecvST (a :?> r) = RemoveRecvST r RemoveRecvST (Sel xs) = Sel (MapRemoveRecv xs) RemoveRecvST (Off xs) = Off (MapRemoveRecv xs) RemoveRecvST (R s) = R (RemoveRecvST s) RemoveRecvST (Wk s) = Wk (RemoveRecvST s) RemoveRecvST s = s -- | Type family for applying a constraint to types of kind `Type` in a session type. It may be applied to a capability. type family HasConstraint (c :: Type -> Constraint) s :: Constraint where HasConstraint c ('Cap ctx s) = (HasConstraintST c s, MapHasConstraint c ctx) -- | Type family for applying a constraint to types of kind `Type` in a session type. It may be applied to a session type. type family MapHasConstraint (c :: Type -> Constraint) ss :: Constraint where MapHasConstraint c '[] = () MapHasConstraint c (s ': ss) = (HasConstraintST c s, MapHasConstraint c ss) -- | Type family for applying a constraint to types of kind `Type` in a list of session types. type family HasConstraintST (c :: Type -> Constraint) s :: Constraint where HasConstraintST c (a :!> r) = (c a, HasConstraintST c r) HasConstraintST c (a :?> r) = (c a, HasConstraintST c r) HasConstraintST c (Sel '[]) = () HasConstraintST c (Sel (s ': xs)) = (HasConstraintST c s, HasConstraintST c (Sel xs)) HasConstraintST c (Off '[]) = () HasConstraintST c (Off (s ': xs)) = (HasConstraintST c s, HasConstraintST c (Off xs)) HasConstraintST c (R s) = HasConstraintST c s HasConstraintST c (Wk s) = HasConstraintST c s HasConstraintST c V = () HasConstraintST c s = () -- | Type family for applying zero or more constraints to types of kind `Type` in a list of session types. It may be applied to a capability. type family HasConstraints (cs :: [Type -> Constraint]) s :: Constraint where HasConstraints '[] s = () HasConstraints (c ': cs) s = (HasConstraint c s, HasConstraints cs s) -- | Type family for applying zero or more constraints to types of kind `Type` in a list of session types. It may be applied to a session type. type family HasConstraintsST (cs :: [Type -> Constraint]) s :: Constraint where HasConstraintsST '[] s = () HasConstraintsST (c ': cs) s = (HasConstraintST c s, HasConstraintsST cs s) -- | Type family for applying zero or more constraints to types of kind `Type` in a list of session types. It may be applied to a list of session types. type family MapHasConstraints (cs :: [Type -> Constraint]) ctx :: Constraint where MapHasConstraints '[] ctx = () MapHasConstraints (c ': cs) ctx = (MapHasConstraint c ctx, MapHasConstraints cs ctx) -- | Promoted `ifThenElse` type family IfThenElse (b :: Bool) (l :: k) (r :: k) :: k where IfThenElse 'True l r = l IfThenElse 'False l r = r -- | Promoted `not` type family Not b :: Bool where Not 'True = 'False Not 'False = 'True -- | Promoted `||` type family Or b1 b2 :: Bool where Or 'True b = 'True Or b 'True = 'True Or b1 b2 = 'False -- | Data type that takes a kind as an argument. Its sole constructor takes two capabilities parameterized by the kind argument. -- -- This data type is useful if it is necessary for an indexed monad to be indexed by four parameters. data Prod t = (:*:) (Cap t) (Cap t) -- | Type family for returning the first argument of a product. type family Left p where Left (l :*: r) = l -- | Type family for returning the second argument of a product. type family Right p where Right (l :*: r) = r -- | Data type defining natural numbers data Nat = Z | S Nat deriving (Show, Eq, Ord) -- | Data type that can give us proof of membership of an element in a list of elements. data Ref s xs where RefZ :: Ref s (s ': xs) RefS :: Ref s (k ': xs) -> Ref s (t ': k ': xs) -- | Type family for computing which types in a list of types are equal to a given type. type family TypeEqList xs s where TypeEqList '[s] s = '[True] TypeEqList '[r] s = '[False] TypeEqList (s ': xs) s = 'True ': TypeEqList xs s TypeEqList (r ': xs) s = 'False ': TypeEqList xs s -- | Promoted `++` type family Append xs ys where Append '[] ys = ys Append (x ': xs) ys = x ': xs `Append` ys