Safe Haskell | Safe |
---|---|
Language | Haskell2010 |
This packages provides a deep embedded domain-specific language for writing session typed program.
A session typed program is a program annotated with session types. A session type describes a communication protocol at the type-level.
The motivation for doing so is that it gives you a static guarantee that a program correctly implements a protocol. It may even guarantee that no deadlocking can occur.
The following constitutes the most important parts of this library for writing session typed programs.
STTerm
: A GADT representing the terms of the DSL. The constructors represent the different session types and are annotated with session types.ST
: A protomoted data type describing the different session types.MonadSession
: A type class exposing the interface of the DSL.- Control.SessionTypes.Indexed: A custom prelude module replacing common type classes with indexed type classes
This package also implements a couple interpreters that evaluate an abstract-syntax tree consisting of STTerm
constructors:
- Control.SessionTypes.Debug: Purely evaluation
- Control.SessionTypes.Interactive: Interactive evaluation
- Control.SessionTypes.Normalize: Rewrites
STTerm
programs to a normal form - Control.SessionTypes.Visualize: Visualizes a session type
- data STTerm :: (Type -> Type) -> Cap a -> Cap a -> Type -> Type where
- Send :: a -> STTerm m (Cap ctx r) r' b -> STTerm m (Cap ctx (a :!> r)) r' b
- Recv :: (a -> STTerm m (Cap ctx r) r' b) -> STTerm m (Cap ctx (a :?> r)) r' b
- Sel1 :: STTerm m (Cap ctx s) r a -> STTerm m (Cap ctx (Sel (s ': xs))) r a
- Sel2 :: STTerm m (Cap ctx (Sel (t ': xs))) r a -> STTerm m (Cap ctx (Sel (s ': (t ': xs)))) r a
- OffZ :: STTerm m (Cap ctx s) r a -> STTerm m (Cap ctx (Off '[s])) r a
- OffS :: STTerm m (Cap ctx s) r a -> STTerm m (Cap ctx (Off (t ': xs))) r a -> STTerm m (Cap ctx (Off (s ': (t ': xs)))) r a
- Rec :: STTerm m (Cap (s ': ctx) s) r a -> STTerm m (Cap ctx (R s)) r a
- Weaken :: STTerm m (Cap ctx t) r a -> STTerm m (Cap (s ': ctx) (Wk t)) r a
- Var :: STTerm m (Cap (s ': ctx) s) t a -> STTerm m (Cap (s ': ctx) V) t a
- Ret :: (a :: Type) -> STTerm m s s a
- Lift :: m (STTerm m s r a) -> STTerm m s r a
- inferIdentity :: STTerm Identity s r a -> STTerm Identity s r a
- class IxMonad m => MonadSession m where
- empty :: MonadSession m => m (Cap '[] s) r a -> m (Cap '[] s) r a
- empty0 :: MonadSession m => m (Cap '[] r) (Cap '[] r) ()
- selN :: MonadSession m => Ref s xs -> m (Cap ctx (Sel xs)) (Cap ctx s) ()
- selN1 :: MonadSession m => m (Cap ctx (Sel (s ': xs))) (Cap ctx s) ()
- selN2 :: MonadSession m => m (Cap ctx (Sel (s ': (t ': xs)))) (Cap ctx t) ()
- selN3 :: MonadSession m => m (Cap ctx (Sel (s ': (t ': (k ': xs))))) (Cap ctx k) ()
- selN4 :: MonadSession m => m (Cap ctx (Sel (s ': (t ': (k ': (r ': xs)))))) (Cap ctx r) ()
- class Select xs s where
- (<&) :: MonadSession m => m (Cap ctx s) r a -> m (Cap ctx (Off (t ': xs))) r a -> m (Cap ctx (Off (s ': (t ': xs)))) r a
- (<&>) :: MonadSession m => m (Cap ctx s) r a -> m (Cap ctx t) r a -> m (Cap ctx (Off '[s, t])) r a
- offer :: MonadSession m => m (Cap ctx s) r a -> m (Cap ctx t) r a -> m (Cap ctx (Off '[s, t])) r a
- recurseFix :: MonadSession m => (m (Cap (s ': ctx) V) r a -> m (Cap (s ': ctx) s) r a) -> m (Cap ctx (R s)) r a
- recurse0 :: MonadSession m => m (Cap ctx (R s)) (Cap (s ': ctx) s) ()
- weaken0 :: MonadSession m => m (Cap (t ': ctx) (Wk s)) (Cap ctx s) ()
- var0 :: MonadSession m => m (Cap (s ': ctx) V) (Cap (s ': ctx) s) ()
- eps0 :: MonadSession m => m (Cap ctx Eps) (Cap ctx Eps) ()
- data ST a
- data Cap a = Cap [ST a] (ST a)
- type family GetST s where ...
- type family GetCtx s where ...
- type family Dual s = r | r -> s where ...
- type family DualST (a :: ST c) = (b :: ST c) | b -> a where ...
- type family MapDual xs = ys | ys -> xs where ...
- type family RemoveSend s where ...
- type family RemoveSendST s where ...
- type family MapRemoveSend ctx where ...
- type family RemoveRecv s where ...
- type family RemoveRecvST s where ...
- type family MapRemoveRecv ctx where ...
- type family HasConstraint (c :: Type -> Constraint) s :: Constraint where ...
- type family HasConstraintST (c :: Type -> Constraint) s :: Constraint where ...
- type family MapHasConstraint (c :: Type -> Constraint) ss :: Constraint where ...
- type family HasConstraints (cs :: [Type -> Constraint]) s :: Constraint where ...
- type family IfThenElse (b :: Bool) (l :: k) (r :: k) :: k where ...
- type family Not b :: Bool where ...
- type family Or b1 b2 :: Bool where ...
- data Prod t = (:*:) (Cap t) (Cap t)
- type family Left p where ...
- type family Right p where ...
- data Nat
- data Ref s xs where
- type family TypeEqList xs s where ...
- type family Append xs ys where ...
STTerm
data STTerm :: (Type -> Type) -> Cap a -> Cap a -> Type -> Type where Source #
The STTerm GADT
Although we say that a STTerm
is annotated with a session type, it is actually annotated with a capability (Cap
).
The capability contains a context that is necessary for recursion and the session type.
The constructors can be split in four different categories:
Send :: a -> STTerm m (Cap ctx r) r' b -> STTerm m (Cap ctx (a :!> r)) r' b | The constructor for sending messages. It is annotated with the send session type ( It takes as an argument, the message to send, of type equal to the first argument of |
Recv :: (a -> STTerm m (Cap ctx r) r' b) -> STTerm m (Cap ctx (a :?> r)) r' b | The constructor for receiving messages. It is annotated with the receive session type ( It takes a continuation that promises to deliver a value that may be used in the rest of the program. |
Sel1 :: STTerm m (Cap ctx s) r a -> STTerm m (Cap ctx (Sel (s ': xs))) r a | Selects the first branch in a selection session type. By selecting a branch, that selected session type must then be implemented. |
Sel2 :: STTerm m (Cap ctx (Sel (t ': xs))) r a -> STTerm m (Cap ctx (Sel (s ': (t ': xs)))) r a | Skips a branch in a selection session type. If the first branch in the selection session type is not the one we want to implement
then we may use |
OffZ :: STTerm m (Cap ctx s) r a -> STTerm m (Cap ctx (Off '[s])) r a | Dually to selection there is also offering branches. Unlike selection, where we may only implement one branch, an offering asks you to implement all branches. Which is chosen depends on how an interpreter synchronizes selection with offering. This constructor denotes the very last branch that may be offered. |
OffS :: STTerm m (Cap ctx s) r a -> STTerm m (Cap ctx (Off (t ': xs))) r a -> STTerm m (Cap ctx (Off (s ': (t ': xs)))) r a | offers a branch and promises at least one more branch to be offered. |
Rec :: STTerm m (Cap (s ': ctx) s) r a -> STTerm m (Cap ctx (R s)) r a | Constructor for delimiting the scope of recursion The recursion constructors also modify or at least make use of the context in the capability. The This is necessary such that we remember the session type of the body of code that we may want to recurse over and thus avoiding infinite type occurrence errors. |
Weaken :: STTerm m (Cap ctx t) r a -> STTerm m (Cap (s ': ctx) (Wk t)) r a | Constructor for weakening (expanding) the scope of recusion This constructor does the opposite of Use this constructor to essentially exit a recursion |
Var :: STTerm m (Cap (s ': ctx) s) t a -> STTerm m (Cap (s ': ctx) V) t a | Constructor that denotes the recursion variable It assumes the context to be non-empty and uses the session type at the top of the context to determine what should be implemented after |
Ret :: (a :: Type) -> STTerm m s s a | Constructor that makes |
Lift :: m (STTerm m s r a) -> STTerm m s r a | Constructor that makes |
Monad m => IxMonadT (Cap a) (STTerm a) m Source # | |
MonadIO m => IxMonadIO (Cap a) (STTerm a m) Source # | |
Monad m => IxMonad (Cap a) (STTerm a m) Source # | |
Monad m => IxApplicative (Cap a) (STTerm a m) Source # | |
IxFunctor (Cap a) (STTerm a m) Source # | |
Monad m => MonadSession (STTerm * m) Source # | |
Monad (STTerm a m s s) Source # | |
Functor (STTerm a m s s) Source # | |
Applicative (STTerm a m s s) Source # | |
inferIdentity :: STTerm Identity s r a -> STTerm Identity s r a Source #
This function can be used if we do not use lift
in a program
but we must still disambiguate m
.
MonadSession
Primitives
class IxMonad m => MonadSession m where Source #
The MonadSession
type class exposes a set of functions that composed together form a session typed program
A type that is an instance of MonadSession
must therefore also be an instance of IxMonad
.
The functions themselves are generally defined as wrappers over corresponding STTerm
constructors.
send :: a -> m (Cap ctx (a :!> r)) (Cap ctx r) () Source #
recv :: m (Cap ctx (a :?> r)) (Cap ctx r) a Source #
sel1 :: m (Cap ctx (Sel (s ': xs))) (Cap ctx s) () Source #
sel2 :: m (Cap ctx (Sel (s ': (t ': xs)))) (Cap ctx (Sel (t ': xs))) () Source #
offZ :: m (Cap ctx s) r a -> m (Cap ctx (Off '[s])) r a Source #
offS :: m (Cap ctx s) r a -> m (Cap ctx (Off (t ': xs))) r a -> m (Cap ctx (Off (s ': (t ': xs)))) r a Source #
recurse :: m (Cap (s ': ctx) s) r a -> m (Cap ctx (R s)) r a Source #
weaken :: m (Cap ctx s) r a -> m (Cap (t ': ctx) (Wk s)) r a Source #
var :: m (Cap (s ': ctx) s) r a -> m (Cap (s ': ctx) V) r a Source #
Combinators
empty :: MonadSession m => m (Cap '[] s) r a -> m (Cap '[] s) r a Source #
A session typed program that is polymorphic in its context can often not be used by interpreters.
We can apply empty
to the session typed program before passing it to an interpreter to instantiate that the context is empty.
empty0 :: MonadSession m => m (Cap '[] r) (Cap '[] r) () Source #
Monadic composable definition of empty
Prefix a session typed program with (empty >>) to instantiate the context to be empty.
selN :: MonadSession m => Ref s xs -> m (Cap ctx (Sel xs)) (Cap ctx s) () Source #
Allows indexing of selections.
The given Ref
type can be used as an indexed to select a branch. This circumvents the need to sequence a bunch of sel1
and sel2
to select a branch.
prog :: MonadSession m => m ('Cap ctx (Sel '[a,b,c,d])) ('Cap ctx Eps) () MonadSession m => m ('Cap ctx b) ('Cap ctx Eps) () prog2 = prog >> selN (RefS RefZ)
selN1 :: MonadSession m => m (Cap ctx (Sel (s ': xs))) (Cap ctx s) () Source #
Select the first branch of a selection.
selN2 :: MonadSession m => m (Cap ctx (Sel (s ': (t ': xs)))) (Cap ctx t) () Source #
Select the second branch of a selection.
selN3 :: MonadSession m => m (Cap ctx (Sel (s ': (t ': (k ': xs))))) (Cap ctx k) () Source #
Select the third branch of a selection.
selN4 :: MonadSession m => m (Cap ctx (Sel (s ': (t ': (k ': (r ': xs)))))) (Cap ctx r) () Source #
Select the fourth branch of a selection.
class Select xs s where Source #
Type class for selecting a branch through injection.
Selects the first branch that matches the given session type.
prog :: MonadSession m => m ('Cap ctx (Sel '[Eps, String :!> Eps, Int :!> Eps])) ('Cap ctx Eps) () prog = sel >> send "c" >>= eps
It should be obvious that you cannot select a branch using sel
if that branch has the same session type as a previous branch.
(<&) :: MonadSession m => m (Cap ctx s) r a -> m (Cap ctx (Off (t ': xs))) r a -> m (Cap ctx (Off (s ': (t ': xs)))) r a infixr 1 Source #
Infix synonym for offS
(<&>) :: MonadSession m => m (Cap ctx s) r a -> m (Cap ctx t) r a -> m (Cap ctx (Off '[s, t])) r a infix 2 Source #
offer :: MonadSession m => m (Cap ctx s) r a -> m (Cap ctx t) r a -> m (Cap ctx (Off '[s, t])) r a Source #
Takes two session typed programs and constructs an offering consisting of two branches
recurseFix :: MonadSession m => (m (Cap (s ': ctx) V) r a -> m (Cap (s ': ctx) s) r a) -> m (Cap ctx (R s)) r a Source #
A fixpoint combinator for recursion
The argument function must take a recursion variable as an argument that can be used to denote the point of recursion.
For example:
prog = recurseFix \f -> do send 5 f
This program will send the number 5 an infinite amount of times.
recurse0 :: MonadSession m => m (Cap ctx (R s)) (Cap (s ': ctx) s) () Source #
Monadic composable definition of recurse
weaken0 :: MonadSession m => m (Cap (t ': ctx) (Wk s)) (Cap ctx s) () Source #
Monadic composable definition of weaken
var0 :: MonadSession m => m (Cap (s ': ctx) V) (Cap (s ': ctx) s) () Source #
Monadic composable definition of var
eps0 :: MonadSession m => m (Cap ctx Eps) (Cap ctx Eps) () Source #
Monadic composable definition of eps
Types
Session Types
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.
A capability that stores a context/scope that is a list of session types and a session type
IxMonad (Cap *) (IxC m) Source # | |
IxApplicative (Cap *) (IxC m) Source # | |
IxFunctor (Cap *) (IxC m) Source # | |
Monad m => IxMonadT (Cap a) (STTerm a) m Source # | |
MonadIO m => IxMonadIO (Cap a) (STTerm a m) Source # | |
Monad m => IxMonad (Cap a) (STTerm a m) Source # | |
Monad m => IxApplicative (Cap a) (STTerm a m) Source # | |
IxFunctor (Cap a) (STTerm a m) Source # | |
Duality
type family Dual s = r | r -> s where ... Source #
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 DualST (a :: ST c) = (b :: ST c) | b -> a where ... Source #
Type family for calculating the dual of a session type. It may be applied to the actual session type.
type family MapDual xs = ys | ys -> xs where ... Source #
Type family for calculating the dual of a list of session types.
Removing
type family RemoveSend s where ... Source #
Type family for removing the send session type from the given session type. It may be applied to a capability.
RemoveSend (Cap ctx s) = Cap (MapRemoveSend ctx) (RemoveSendST s) |
type family RemoveSendST s where ... Source #
Type family for removing the send session type from the given session type. It may be applied to a session type.
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 MapRemoveSend ctx where ... Source #
Type family for removing the send session type from a list of session types.
MapRemoveSend '[] = '[] | |
MapRemoveSend (s ': ctx) = RemoveSendST s ': MapRemoveSend ctx |
type family RemoveRecv s where ... Source #
Type family for removing the receive session type from the given session type. It may be applied to a capability.
RemoveRecv (Cap ctx s) = Cap (MapRemoveRecv ctx) (RemoveRecvST s) |
type family RemoveRecvST s where ... Source #
Type family for removing the receive session type from a list of session types.
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 MapRemoveRecv ctx where ... Source #
Type family for removing the receive session type from the given session type. It may be applied to a session type.
MapRemoveRecv '[] = '[] | |
MapRemoveRecv (s ': ctx) = RemoveRecvST s ': MapRemoveRecv ctx |
Applying Constraints
type family HasConstraint (c :: Type -> Constraint) s :: Constraint where ... Source #
Type family for applying a constraint to types of kind Type
in a session type. It may be applied to a capability.
HasConstraint c (Cap ctx s) = (HasConstraintST c s, MapHasConstraint c ctx) |
type family HasConstraintST (c :: Type -> Constraint) s :: Constraint where ... Source #
Type family for applying a constraint to types of kind Type
in a list of session types.
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 MapHasConstraint (c :: Type -> Constraint) ss :: Constraint where ... Source #
Type family for applying a constraint to types of kind Type
in a session type. It may be applied to a session type.
MapHasConstraint c '[] = () | |
MapHasConstraint c (s ': ss) = (HasConstraintST c s, MapHasConstraint c ss) |
type family HasConstraints (cs :: [Type -> Constraint]) s :: Constraint where ... Source #
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.
HasConstraints '[] s = () | |
HasConstraints (c ': cs) s = (HasConstraint c s, HasConstraints cs s) |
Boolean functions
type family IfThenElse (b :: Bool) (l :: k) (r :: k) :: k where ... Source #
Promoted ifThenElse
IfThenElse True l r = l | |
IfThenElse False l r = r |
Product type
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.
Other
Data type defining natural numbers
Data type that can give us proof of membership of an element in a list of elements.
type family TypeEqList xs s where ... Source #
Type family for computing which types in a list of types are equal to a given type.
TypeEqList '[s] s = '[True] | |
TypeEqList '[r] s = '[False] | |
TypeEqList (s ': xs) s = True ': TypeEqList xs s | |
TypeEqList (r ': xs) s = False ': TypeEqList xs s |