-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/
-- | Session types distributed
--
-- This package serves as a wrapper over both the Cloud Haskell library
-- (distributed-process) and the sessiontypes library. It provides an
-- interpreter for evaluating session typed programs to Cloud Haskell
-- programs and exposes several combinators for spawning sessions.
@package sessiontypes-distributed
@version 0.1.1
-- | Defines a session typed channel as a wrapper over the typed channel
-- from Cloud Haskell
--
-- We define a session typed channel to overcome the limitation of a
-- typed channel that can only send and receive messages of a single
-- type.
--
-- Underneath we actually do the same, and make use of
-- unsafeCoerce to coerce a value's type to that described in the
-- session typed.
--
-- Session types do not entirely guarantee safety of using
-- unsafeCoerce. One can use the same session typed send port over
-- and over again, while the correpsonding receive port might progress
-- through the session type resulting in a desync of types between the
-- send and receive port.
--
-- It is for this reason recommended to always make use of
-- STChannelT that always progresses the session type of a port
-- after a session typed action.
module Control.Distributed.Session.STChannel
-- | Basic message type that existentially quantifies the content of the
-- message
data Message
Message :: a -> Message
-- | Session typed send port as a wrapper over SendPort Message. It is
-- parameterized with a capability/sessiontype.
data STSendPort (l :: Cap Type)
STSendPort :: (SendPort Message) -> STSendPort
-- | Session typed receive port as a wrapper over ReceivePort Message. It
-- is parameterized with a capability/sessiontype.
data STReceivePort (l :: Cap Type)
STReceivePort :: (ReceivePort Message) -> STReceivePort
-- | Type synonym for a session typed channel given a single session type
--
-- This removes recv session types from the given session type as it is
-- passed to the send port type
--
-- Also removes send session types from the given session type as it is
-- passed to the receive port type
type STChan s = (STSendPort (RemoveRecv s), STReceivePort (RemoveSend s))
-- | Same as STChan, but it is given a session type for the send
-- port type and a separate session type for the receive port type
type STChanBi s r = (STSendPort (RemoveRecv s), STReceivePort (RemoveSend r))
-- | Unsession typed typed channel
--
-- It is essentially just a typed channel that is parameterized with
-- Message.
--
-- We can carry around this type in Session, but not a
-- STChan.
type UTChan = (SendPort Message, ReceivePort Message)
-- | Creates a new session typed channel given a single session type
newSTChan :: Proxy s -> Process (STChan s)
-- | Creates a new session typed channel given separate session types for
-- the send port and receive port
newSTChanBi :: Proxy s -> Proxy r -> Process (STChanBi s r)
-- | Creates an unsession typed channel
newUTChan :: Process UTChan
-- | Converts an unsession typed channel to a session typed channel
toSTChan :: UTChan -> Proxy s -> STChan s
-- | Converts an unsession typed channel to a session typed channel
toSTChanBi :: UTChan -> Proxy s -> Proxy r -> STChanBi s r
-- | Converts a session typed send port into a Proxy
sendProxy :: STSendPort s -> Proxy s
-- | Converts a session typed receive port into a Proxy
recvProxy :: STReceivePort s -> Proxy s
-- | Sends a message using a session typed send port
sendSTChan :: Serializable a => STSendPort ( 'Cap ctx (a :!> l)) -> a -> Process (STSendPort ( 'Cap ctx l))
-- | Receives a message using a session typed receive port
recvSTChan :: Serializable a => STReceivePort ( 'Cap ctx (a :?> l)) -> Process (a, STReceivePort ( 'Cap ctx l))
-- | Type class that defines combinators for branching on a session typed
-- port
class STSplit (m :: Cap Type -> Type)
-- | select the first branch of a selection using the given port
sel1Chan :: STSplit m => m ( 'Cap ctx (Sel (s : xs))) -> m ( 'Cap ctx s)
-- | select the second branch of a selection using the given port
sel2Chan :: STSplit m => m ( 'Cap ctx (Sel (s : (t : xs)))) -> m ( 'Cap ctx (Sel (t : xs)))
-- | select the first branch of an offering using the given port
off1Chan :: STSplit m => m ( 'Cap ctx (Off (s : xs))) -> m ( 'Cap ctx s)
-- | select the second branch of an offering using the given port
off2Chan :: STSplit m => m ( 'Cap ctx (Off (s : (t : xs)))) -> m ( 'Cap ctx (Off (t : xs)))
-- | Type class for recursion on a session typed port
class STRec (m :: Cap Type -> Type)
recChan :: STRec m => m ( 'Cap ctx (R s)) -> m ( 'Cap (s : ctx) s)
wkChan :: STRec m => m ( 'Cap (t : ctx) (Wk s)) -> m ( 'Cap ctx s)
varChan :: STRec m => m ( 'Cap (s : ctx) V) -> m ( 'Cap (s : ctx) s)
-- | Indexed monad transformer that is indexed by two products of session
-- types
--
-- This monad also acts as a state monad that whose state is defined by a
-- session typed channel and dependent on the indexing of the monad.
data STChannelT m (p :: Prod Type) (q :: Prod Type) a
STChannelT :: ((STSendPort (Left p), STReceivePort (Right p)) -> m (a, (STSendPort (Left q), STReceivePort (Right q)))) -> STChannelT m a
[runSTChannelT] :: STChannelT m a -> ((STSendPort (Left p), STReceivePort (Right p)) -> m (a, (STSendPort (Left q), STReceivePort (Right q))))
-- | Send a message
--
-- Only the session type of the send port needs to be adjusted
sendSTChanM :: Serializable a => a -> STChannelT Process ( 'Cap ctx (a :!> l) :*: r) ( 'Cap ctx l :*: r) ()
-- | receive a message
--
-- Only the session type of the receive port needs to be adjusted
recvSTChanM :: Serializable a => STChannelT Process (l :*: ( 'Cap ctx (a :?> r))) (l :*: 'Cap ctx r) a
-- | select the first branch of a selection
--
-- Both ports are now adjusted. This is similarly so for the remaining
-- combinators.
sel1ChanM :: STChannelT Process ( 'Cap lctx (Sel (l : ls)) :*: ( 'Cap rctx (Sel (r : rs)))) ( 'Cap lctx l :*: 'Cap rctx r) ()
-- | select the second branch of a selection
sel2ChanM :: STChannelT Process ( 'Cap lctx (Sel (s1 : (t1 : xs1))) :*: 'Cap rctx (Sel (s2 : (t2 : xs2)))) ( 'Cap lctx (Sel (t1 : xs1)) :*: 'Cap rctx (Sel (t2 : xs2))) ()
-- | select the first branch of an offering
off1ChanM :: STChannelT Process ( 'Cap lctx (Off (l : ls)) :*: ( 'Cap rctx (Off (r : rs)))) ( 'Cap lctx l :*: 'Cap rctx r) ()
-- | select the second branch of an offering
off2ChanM :: STChannelT Process ( 'Cap lctx (Off (s1 : (t1 : xs1))) :*: 'Cap rctx (Off (s2 : (t2 : xs2)))) ( 'Cap lctx (Off (t1 : xs1)) :*: 'Cap rctx (Off (t2 : xs2))) ()
-- | delimit scope of recursion
recChanM :: STChannelT Process ( 'Cap sctx (R s) :*: 'Cap rctx (R r)) ( 'Cap (s : sctx) s :*: 'Cap (r : rctx) r) ()
-- | weaken scope of recursion
wkChanM :: STChannelT Process ( 'Cap (t : sctx) (Wk s) :*: 'Cap (k : rctx) (Wk r)) ( 'Cap sctx s :*: 'Cap rctx r) ()
-- | recursion variable (recurse here)
varChanM :: STChannelT Process (( 'Cap (s : sctx) V) :*: ( 'Cap (r : rctx) V)) ( 'Cap (s : sctx) s :*: 'Cap (r : rctx) r) ()
-- | ports are no longer usable
epsChanM :: STChannelT Process ( 'Cap ctx Eps :*: 'Cap ctx Eps) ( 'Cap ctx Eps :*: 'Cap ctx Eps) ()
instance GHC.Base.Monad m => Control.SessionTypes.Indexed.IxFunctor (Control.Distributed.Session.STChannel.STChannelT m)
instance GHC.Base.Monad m => Control.SessionTypes.Indexed.IxApplicative (Control.Distributed.Session.STChannel.STChannelT m)
instance GHC.Base.Monad m => Control.SessionTypes.Indexed.IxMonad (Control.Distributed.Session.STChannel.STChannelT m)
instance GHC.Base.Monad m => Control.SessionTypes.Indexed.IxMonadT Control.Distributed.Session.STChannel.STChannelT m
instance Control.Distributed.Session.STChannel.STRec Control.Distributed.Session.STChannel.STSendPort
instance Control.Distributed.Session.STChannel.STRec Control.Distributed.Session.STChannel.STReceivePort
instance Control.Distributed.Session.STChannel.STSplit Control.Distributed.Session.STChannel.STSendPort
instance Control.Distributed.Session.STChannel.STSplit Control.Distributed.Session.STChannel.STReceivePort
instance Data.Binary.Class.Binary Control.Distributed.Session.STChannel.Message
-- | This module defines the Session session typed indexed monad.
module Control.Distributed.Session.Session
-- | Session is defined as a newtype wrapper over a function that
-- takes a `Maybe SessionInfo` and returns an indexed codensity monad
-- transformer over the Process monad.
--
-- Session is also a reader monad that has a Maybe SessionInfo as
-- its environment. SessionInfo is wrapped in a Maybe,
-- because we also allow a session to be run singularly. In which case
-- there is no other Session to communicate with and therefore is there
-- also no need for a SessionInfo.
--
-- The function returns the indexed codensity monad and not simply a
-- STTerm, because from benchmarking the codensity monad gave us
-- significant performance improvements for free.
newtype Session s r a
Session :: (Maybe SessionInfo -> IxC Process s r a) -> Session s r a
[runSessionC] :: Session s r a -> Maybe SessionInfo -> IxC Process s r a
-- | The SessionInfo data type tells us information about another
-- Session. Namely, the Session that is in a session with
-- the Session that this specific SessionInfo belongs to.
data SessionInfo
SessionInfo :: ProcessId -> NodeId -> UTChan -> SessionInfo
-- | The ProcessId of the dual Session
[othPid] :: SessionInfo -> ProcessId
-- | The NodeId of the Node that the dual Session
-- runs on
[othNode] :: SessionInfo -> NodeId
-- | A send port belonging to the dual Session, such that we can
-- send messages to it. And a receive port of which the dual
-- Session has its send port, such that we can receive messages
-- from the dual Session.
[utchan] :: SessionInfo -> UTChan
-- | Evaluates a session to a STTerm
runSession :: Session s r a -> Maybe SessionInfo -> STTerm Process s r a
-- | Lifts a Process computation
liftP :: Process a -> Session s s a
-- | Lifts a STTerm computation
liftST :: STTerm Process s r a -> Session s r a
instance Control.SessionTypes.Indexed.IxFunctor Control.Distributed.Session.Session.Session
instance Control.SessionTypes.Indexed.IxApplicative Control.Distributed.Session.Session.Session
instance Control.SessionTypes.Indexed.IxMonad Control.Distributed.Session.Session.Session
instance Control.SessionTypes.MonadSession.MonadSession Control.Distributed.Session.Session.Session
instance Control.SessionTypes.Indexed.IxMonadReader (GHC.Base.Maybe Control.Distributed.Session.Session.SessionInfo) Control.Distributed.Session.Session.Session
instance Control.SessionTypes.Indexed.IxMonadIO Control.Distributed.Session.Session.Session
-- | This module provides three functions for normalizing session typed
-- programs.
--
-- With normalizing we mean that we apply rewrites to a session typed
-- program until we can no longer do so and that do not change the
-- semantics of the program.
--
-- The motivation for this module is that for two session typed programs
-- to run as a session they must be dual. Sometimes, one of these
-- programs might not have a session type that is dual to the session
-- type of the other program,
--
-- but we can rewrite the program and therefore also its session type. It
-- is of course important that we do not alter the semantics of the
-- program when rewriting it. For that reason, any rewrite that we may
-- apply must be isomorphic.
--
-- A rewrite is isomorphic if we have two programs p and p', we can do a
-- rewrite from p to p' and from p' to p.
--
-- For now two types of rewrites are applied: Elimination of recursive
-- types and flattening of branches.
--
-- An additional benefit of normalizing is that it may lead to further
-- optimizations.
--
-- In Control.Distributed.Session.Eval we send an integer for
-- every Sel session type that we encounter. By flattening
-- branching we reduce the number of Sel constructors and
-- therefore also the number of times one needs to communicate an
-- integer.
module Control.Distributed.Session.Normalize
-- | Applies two types of rewrites to a Session.
--
--
-- - Elimination of unused recursion
-- - Rewrites non-right nested branchings to right nested
-- branchings
--
normalize :: Normalize s s' => Session s ( 'Cap '[] Eps) a -> Session s' ( 'Cap '[] Eps) a
-- | Function for eliminating unused recursive types.
--
-- The function elimRec takes a Session and traverses the
-- underlying STTerm. While doing so, it will attempt to remove
-- STTerm constructors annotated with R or Wk from
-- the program if in doing so does not change the behavior of the
-- program.
--
-- For example, in the following session type we may remove the inner
-- R and the Wk.
--
--
-- R (R (Wk V))
--
--
-- We have that the outer R matches the recursion variable because
-- of the use of Wk.
--
-- That means the inner R does not match any recursion variable
-- (the R is unused) and therefore may it and its corresponding
-- constructor be removed from the session.
--
-- We also remove the Wk, because the session type pushed into the
-- context by the inner R has also been removed.
--
-- The generated session type is
--
--
-- R V
--
elimRec :: ElimRec s s' => Session s ( 'Cap '[] Eps) a -> Session s' ( 'Cap '[] Eps) a
-- | Flattening of branching
--
-- The function flatten takes a Session and traverses the
-- underlying STTerm. If it finds a branching session type that
-- has a branch starting with another branching of the same type, then it
-- will extract the branches of the inner branching and inserts these
-- into the outer branching. This is similar to flattening a list of
-- lists to a larger list.
--
-- For example:
--
--
-- Sel '[a,b, Sel '[c,d], e]
--
--
-- becomes
--
--
-- Sel '[a,b,c,d,e]
--
--
-- This only works if the inner branching has the same type as the outer
-- branch (Sel in Sel or Off in Off).
--
-- Also, for now this rewrite only works if one of the branching of the
-- outer branch starts with a new branching.
--
-- For example:
--
--
-- Sel '[a,b, Int :!> Sel '[c,d],e]
--
--
-- does not become
--
--
-- Sel '[a,b,Int :!> c, Int :!> d, e]
--
--
-- Although, this is something that will be added in the future.
flatten :: Flatten s s' => Session s ( 'Cap '[] Eps) a -> Session s' ( 'Cap '[] Eps) a
-- | This module exposes two functions for interactively evaluation a
-- session typed program
--
-- To run a session you must have two participating actors. In our
-- context, the actors are session typed programs.
--
-- Using this module the user will act as one of the actors in the
-- session by suppling values to a receive
--
-- and selecting a branch for offerings.
module Control.Distributed.Session.Interactive
-- | For this function the user will act as the dual to the given session.
-- User interaction is only required when the given program does a
-- receive or an offer.
--
-- A possible interaction goes as follows:
--
--
-- prog = do
-- send 5
-- x <- recv
-- offer (eps x) (eps "")
--
-- main = interactive prog
--
--
--
-- > Enter value of type String: "test"
-- > (L)eft or (R)ight: L
-- "test"
--
interactive :: (HasConstraints '[Read, Show, Typeable] s, Show a) => Session s r a -> Process a
-- | Different from interactive is that this function gives the user
-- the choice to abort the session after each session typed action.
--
-- Furthermore, it also prints additional output describing which session
-- typed action occurred.
interactiveStep :: (HasConstraints '[Read, Show, Typeable] s, Show a) => Session s r a -> Process (Maybe a)
-- | This module defines two interpreters for mapping the Cloud Haskell
-- semantics to the constructors of STTerm.
module Control.Distributed.Session.Eval
-- | This function unpacks a Session to a STTerm using a
-- given SessionInfo.
--
-- It then evaluates the STTerm by mapping Cloud Haskell semantics
-- to each constructor of STTerm.
--
-- The function relies on that there exists another session (on a
-- different process) that is also being evaluated (using evalSession)
-- and acts as the dual the session that function is now evaluating.
--
-- The underlying communication method is a session typed channel
-- (STChannelT). There should be no interference from other
-- processes, unless you go through the effort of sharing the send port.
evalSession :: forall s r a. HasConstraint Serializable s => Session s r a -> SessionInfo -> Process a
-- | Similar to evalSession, except for that it does not evaluate
-- session typed actions.
--
-- Only returns and lifted computations are evaluated. This also means
-- that there does not need to be a dual session that is evaluated on a
-- different process.
--
-- It also assumes that SessionInfo is not used. Use
-- evalSessionEq' if this is not the case.
evalSessionEq :: Session s s a -> Process a
-- | Same as evalSessionEq, but you may now provide a
-- SessionInfo.
evalSessionEq' :: Session s s a -> SessionInfo -> Process a
-- | Provides instances for Session of IxMonadThrow,
-- IxMonadCatch and IxMonadMask.
--
-- These instances should behave no differently from the corresponding
-- MonadThrow, MonadCatch and MonadMask instances
-- for Process. For more documentation please visit
-- Control.Monad.Catch
--
-- The reason that the instances are placed in a separate module is to
-- avoid a circular dependency of the modules.
--
-- The instances require evaluation of the sessions, therefore
-- Control.Distributed.Session.Eval should be imported.
--
-- However that module imports
-- Control.Distributed.Session.Session. Placing these instances in
-- this module would then require importing
-- Control.Distributed.Session.Eval causing a circular dependency.
--
-- Note that these instances are already exported by
-- Control.Distributed.Session, such that this module should need
-- no explicit import.
module Control.Distributed.Session.Exception
instance Control.SessionTypes.Indexed.IxMonadThrow Control.Distributed.Session.Session.Session s
instance Control.SessionTypes.Indexed.IxMonadCatch Control.Distributed.Session.Session.Session s
instance Control.SessionTypes.Indexed.IxMonadMask Control.Distributed.Session.Session.Session s
-- | This module describes an interpreter for purely evaluating session
-- typed programs
--
-- that is based on the paper Beauty in the beast by Swierstra,
-- W., & Altenkirch, T.
--
-- Impurity in a session typed programs mainly comes from three things:
-- receives, branching and lifting.
--
--
-- - Using the session type we can easily determine the type of the
-- message that each receive should expect. This information allows us to
-- define a stream of values of different types that provides input for
-- each receive.
-- - When evaluating a session we send and receive integers to choose a
-- branch in a selection and offering respectively. If we want to purely
-- evaluate a session typed program, then we must provide some kind of
-- input that makes this choice for us.
-- - The current structure of the Lift constructor does not
-- allow us to purely evaluate a Lift. As such a session typed
-- program may not contain a lift for it to be purely evaluated. See
-- runM as an alternative.
--
module Control.Distributed.Session.Debug
-- | Purely evaluates a given Session using the input defined by
-- Stream.
--
-- The output is described in terms of the session type actions within
-- the given program
--
-- An example of how to use this function goes as follows:
--
--
-- prog :: Session ('Cap '[] (Int :!> String :?> Eps)) ('Cap '[] Eps) String
-- prog = send 5 >> recv >>= eps
--
-- strm = S_Send $ S_Recv "foo" S_Eps
--
--
--
-- >>> run prog strm
-- O_Send 5 $ O_Recv "foo" $ O_Eps "foo"
--
run :: HasConstraint Show s => Session s ( 'Cap ctx Eps) a -> Stream s -> Output s a
-- | Instead of describing the session typed actions, it returns a list of
-- the results of all branches of all offerings.
--
--
-- prog = offer (eps 10) (eps 5)
-- strm = S_OffS S_Eps S_Eps
--
--
--
-- >>> runAll prog strm
-- [10,5]
--
runAll :: HasConstraint Show s => Session s ( 'Cap ctx Eps) a -> Stream s -> [a]
-- | Same as runAll but applies head to the resulting list
--
--
-- >>> runSingle prog strm
-- 10
--
runSingle :: HasConstraint Show s => Session s ( 'Cap ctx Eps) a -> Stream s -> a
-- | run cannot deal with lifted computations. This makes it limited
-- to session typed programs without any use of lift.
--
-- This function allows us to evaluate lifted computations, but as a
-- consequence is no longer entirely pure.
runP :: HasConstraint Show s => Session s ( 'Cap ctx Eps) a -> SessionInfo -> Stream s -> Process (Output s a)
-- | Monadic version of runAll.
runAllP :: HasConstraint Show s => Session s ( 'Cap ctx Eps) a -> SessionInfo -> Stream s -> Process [a]
-- | Monad version of runSingle
runSingleP :: HasConstraint Show s => Session s ( 'Cap ctx Eps) a -> SessionInfo -> Stream s -> Process a
-- | Session typed version of runP
runM :: HasConstraint Show s => Session s ( 'Cap ctx Eps) a -> Stream s -> Session r r (Output s a)
-- | Session typed version of runAllP
runAllM :: HasConstraint Show s => Session s ( 'Cap ctx Eps) a -> Stream s -> Session r r [a]
-- | Session typed version of runSingleP
runSingleM :: HasConstraint Show s => Session s ( 'Cap ctx Eps) a -> Stream s -> Session r r a
-- | We use the Stream data type to supply input for the receives in
-- a session typed programs.
--
-- We annotate a Stream with a capability for the following three
-- reasons:
--
--
-- - Each recv may return a value of a different type.
-- - Given reason 1 and that we can have branching, we must also be
-- able to branch in the stream.
-- - We can now write a function that recursively generates input for a
-- recursive program
--
--
-- Similar to STTerm, Stream has a constructor for each
-- session type. Each constructor takes an argument that is another
-- Stream type, except for S_Recv that takes an additional
-- argument that will be used as input, and S_Eps that denotes the
-- end of the stream.
--
-- At first it might be confusing which constructors and in what order
-- these constructors should be placed to form a Stream that can
-- be used as input for some STTerm.
--
-- This is actually not that difficult at all. A Stream is session
-- typed and that session type must be equal to the session type of the
-- STTerm. As such one merely needs to create a Stream that
-- has the same session type and if you don't the type checker will tell
-- you what it incorrect.
--
-- There are two things that you need to be aware of when constructor a
-- Stream.
--
--
-- - The Stream constructors for offering (S_OffZ and S_OffS)
-- require that you define input for all branches of the offering. This
-- can be quite cumbersome, so we include a S_Off1 and
-- S_Off2 constructor that behave similarly to S_Sel1 and
-- S_Sel2.
-- - You are not guaranteed that a Stream can be used for all
-- session typed programs that have the same session type. Specifically
-- when it comes to selection can we not guarantee this. The session type
-- for selection only tells us about which branches could be selected. It
-- does not tell us which branch was selected as this is runtime
-- dependent.
--
data Stream (a :: Cap Type) :: Cap Type -> Type
[S_Send] :: Stream Cap Type ctx (:!>) Type a1 s
[S_Recv] :: Stream Cap Type ctx (:?>) * a1 s
[S_Sel1] :: Stream Cap Type ctx Sel Type (:) ST Type s xs
[S_Sel2] :: Stream Cap Type ctx Sel Type (:) ST Type s (:) ST Type t xs
[S_OffZ] :: Stream Cap Type ctx Off Type (:) ST Type s [] ST Type
[S_OffS] :: Stream Cap Type ctx Off Type (:) ST Type s (:) ST Type t xs
[S_Off1] :: Stream Cap Type ctx Off Type (:) ST Type s xs
[S_Off2] :: Stream Cap Type ctx Off Type (:) ST Type s (:) ST Type t xs
[S_Rec] :: Stream Cap Type ctx R Type s
[S_Weaken] :: Stream Cap Type (:) ST Type t ctx Wk Type s
[S_Var] :: Stream Cap Type (:) ST Type s ctx V Type
[S_Eps] :: Stream Cap Type [] ST Type Eps Type
-- | The Output data type describes the session type actions that
-- were done
data Output (a :: Cap Type) b :: Cap Type -> Type -> Type
[O_Send] :: Output Cap Type ctx (:!>) * a1 r b
[O_Recv] :: Output Cap Type ctx (:?>) * a1 r b
[O_Sel1] :: Output Cap Type ctx Sel Type (:) ST Type s xs b
[O_Sel2] :: Output Cap Type ctx Sel Type (:) ST Type s xs b
[O_OffZ] :: Output Cap Type ctx Off Type (:) ST Type s [] ST Type b
[O_OffS] :: Output Cap Type ctx Off Type (:) ST Type s (:) ST Type t xs b
[O_Off1] :: Output Cap Type ctx Off Type (:) ST Type s xs b
[O_Off2] :: Output Cap Type ctx Off Type (:) ST Type s (:) ST Type t xs b
[O_Rec] :: Output Cap Type ctx R Type s b
[O_Var] :: Output Cap Type (:) ST Type s ctx V Type b
[O_Weaken] :: Output Cap Type (:) ST Type t ctx Wk Type s b
[O_Eps] :: Output Cap Type [] ST Type Eps Type b
[O_Lift] :: Output a b
-- | We cannot create a Closure of a Session, because its
-- type parameters are of a different kind than *.
--
-- To accomedate for this drawback we define two data types that
-- existentially quantify the type parameters of a Session.
--
-- We also define a set of static and closure functions for remotely
-- spawning sessions.
module Control.Distributed.Session.Closure
-- | Data type that encapsulates two sessions for the purpose of remotely
-- spawning them
--
-- The session types of the sessions are existentially quantified, but we
-- still ensure duality and constrain them properly, such that they can
-- be passed to evalSession.
data SpawnSession a b
[SpawnSession] :: (HasConstraintST Serializable s, HasConstraintST Serializable (DualST s), Typeable a, Typeable b) => Session ( 'Cap '[] s) r a -> Session ( 'Cap '[] (DualST s)) r b -> SpawnSession a b
-- | Data type that encapsulates a single session performing no session
-- typed action that can be remotely spawned.
--
-- We use this data type mostly for convenience in combination with
-- evalSessionEq allowing us to avoid the Serializable
-- constraint.
data SessionWrap a
[SessionWrap] :: Session s s a -> SessionWrap a
-- | RemoteTable that binds all in this module defined static functions to
-- their corresponding evaluation functions.
sessionRemoteTable :: RemoteTable -> RemoteTable
-- | Static function for remotely spawning a single session
--
-- When remotely spawning any session we must always pass it the
-- ProcessId and NodeId of the spawning process.
--
-- We must pass a Closure of a SessionWrap instead of just a
-- SessionWrap, because that would require serializing a
-- SessionWrap which is not possible.
--
-- Furthermore, we must also pass a SerializableDict that shows
-- how to serialize a value of type a.
remoteSessionStatic :: Static (SerializableDict a -> Closure (SessionWrap a) -> Process a)
-- | Closure function for remotely spawning a single session
remoteSessionClosure :: Static (SerializableDict a) -> Closure (SessionWrap a) -> Closure (Process a)
-- | Same as remoteSessionStatic, except that we do not need to
-- provide a SerializableDict.
remoteSessionStatic' :: Static (Closure (SessionWrap ()) -> Process ())
-- | Same as remoteSessionClosure, except that we do not need to
-- provide a SerializableDict.
remoteSessionClosure' :: Closure (SessionWrap ()) -> Closure (Process ())
-- | A static function specific to the lifted spawnChannel function
-- that can be found in Control.Distributed.Session.Lifted
spawnChannelStatic :: Static (SerializableDict a -> Closure (ReceivePort a -> SessionWrap ()) -> ReceivePort a -> Process ())
-- | A closure specific to the lifted spawnChannel function that can
-- be found in Control.Distributed.Session.Lifted
spawnChannelClosure :: Static (SerializableDict a) -> Closure (ReceivePort a -> SessionWrap ()) -> Closure (ReceivePort a -> Process ())
-- | Function that evalutes the first argument of a SpawnSession in
-- a local manner.
--
-- It is local in that we do not create an accompanying closure.
evalLocalSession :: Typeable a => (ProcessId, NodeId, Closure (SpawnSession a ())) -> Process a
-- | Static function for remotely evaluating the second argument of a
-- SpawnSession.
--
-- This function works dually to evalLocalSession.
remoteSpawnSessionStatic :: Static (SerializableDict a -> (ProcessId, NodeId, Closure (SpawnSession a ())) -> Process ())
-- | Closure for remotely evaluating the second argument of a
-- SpawnSession
remoteSpawnSessionClosure :: Static (SerializableDict a) -> (ProcessId, NodeId, Closure (SpawnSession a ())) -> Closure (Process ())
-- | Same as remoteSpawnSessionStatic, except for that we do not
-- need to provide a SerializableDict.
remoteSpawnSessionStatic' :: Static ((ProcessId, NodeId, Closure (SpawnSession () ())) -> Process ())
-- | Same as remoteSpawnSessionClosure, except for that we do not
-- need to provide a SerializableDict.
remoteSpawnSessionClosure' :: (ProcessId, NodeId, Closure (SpawnSession () ())) -> Closure (Process ())
-- | Static function for remotely evaluating the second argument of a
-- SpawnSession
--
-- This function is very similar to remoteSpawnSessionStatic'. The
-- difference is that this function assumes that the other session was
-- also remotely spawned.
--
-- Therefore we require an extra send of the ProcessId of the to
-- be spawned process.
rrSpawnSessionSendStatic :: Static ((ProcessId, NodeId, Closure (SpawnSession () ())) -> Process ())
-- | Closure for remotely evaluating the second argument of a
-- SpawnSession.
rrSpawnSessionSendClosure :: (ProcessId, NodeId, Closure (SpawnSession () ())) -> Closure (Process ())
-- | Closure for remotely evaluating the first argument of a
-- SpawnSession
--
-- This function acts dual to rrSpawnSessionSend and assumes that
-- it will first receive a ProcessId.
rrSpawnSessionExpectStatic :: Static ((NodeId, Closure (SpawnSession () ())) -> Process ())
-- | Closure for remotely evaluating the first argument of a
-- SpawnSession.
rrSpawnSessionExpectClosure :: (NodeId, Closure (SpawnSession () ())) -> Closure (Process ())
-- | In this module we lift all functions in
-- Control.Distributed.Process that return a function of type
-- Process a to Session s s a.
--
-- Since the functions in this module work identical to the ones in
-- Control.Distributed.Process we will refer to that module for
-- documentation.
--
-- There is however some explanation required for functions that take a
-- Process as an argument.
--
-- For the functions that also take a Process a as an argument we derive
-- two functions. One that still takes a Process a and one that takes a
-- Session s s a.
--
-- There are also functions that take a Closure (Process ()) as an
-- argument. We cannot lift this to be Closure (Session s s ()) as is
-- explained in Control.Distributed.Session.Closure.
--
-- To accomodate for this drawback we instead have these functions take a
-- Closure (SessionWrap ()) as an argument.
--
-- Here is an example on how to call call.
--
--
-- {-# LANGUAGE TemplateHaskell #-}
-- import qualified SessionTypes.Indexed as I
-- import Control.Distributed.Session (SessionWrap(..), sessionRemoteTable, call, evalSessionEq)
-- import Control.Distributed.Process (liftIO, Process, RemoteTable, NodeId)
-- import Control.Distributed.Process.Serializable (SerializableDict(..))
-- import Control.Distributed.Process.Closure (remotable, mkStaticClosure, mkStatic)
-- import Control.Distributed.Process.Node
-- import Network.Transport.TCP
--
-- sessWrap :: SessionWrap Int
-- sessWrap = SessionWrap $ I.return 5
--
-- sdictInt :: SerializableDict Int
-- sdictInt = SerializableDict
--
-- remotable ['sdictInt, 'sessWrap]
--
-- p1 :: NodeId -> Process ()
-- p1 nid = do
-- a <- evalSessionEq (call $(mkStatic 'sdictInt) nid $(mkStaticClosure 'sessWrap))
-- liftIO $ putStrLn $ show a
--
-- myRemoteTable :: RemoteTable
-- myRemoteTable = Main.__remoteTable $ sessionRemoteTable initRemoteTable
--
-- main :: IO ()
-- main = do
-- Right t <- createTransport "127.0.0.1" "100000" defaultTCPParameters
-- node <- newLocalNode t myRemoteTable
-- runProcess node $ p1 (localNodeId node)
--
--
--
-- >>> main
-- > 5
--
--
-- In p1 we run a session that makes a call and then prints out the
-- result of that call.
--
-- Note that this is the call function from
-- SessionTyped.Distributed.Process.Lifted. It takes a Static
-- (SerializableDict a) and a Closure (SessionWrap a).
--
-- To create a static serializable dictionary we first have to define a
-- function that returns a monomorphic serializable dictionary.
--
--
-- sdictInt :: SerializableDict Int
-- sdictInt = SerializableDict
--
--
-- We then pass 'sdictInt to remoteable, which is a top-level Template
-- Haskell splice.
--
--
-- remoteable ['sdictInt]
--
--
-- Now we can create a static serializable dictionary with
--
--
-- $(mkStatic 'sdictInt)
--
--
-- To create a closure for a Session s s we have to wrap it in a
-- SessionWrap.
--
--
-- sessWrap :: SessionWrap Int
-- sessWrap = SessionWrap $ I.return 5
--
--
-- Similarly to sdictInt this needs to be a top level definition such
-- that we can use Template Haskell to derive a Closure
--
--
-- remotable ['sdictInt, 'sessWrap]
-- $(mkStaticClosure 'sessWrap)
--
--
-- Since call makes use of internally defined closures, you also
-- have to include sessionRemoteTable.
--
--
-- myRemoteTable = Main.__remoteTable $ sessionRemoteTable initRemoteTable
--
--
-- The remote tables contains a mapping from labels to evaluation
-- functions that a node uses to evaluate closures.
--
--
-- node <- newLocalNode t myRemoteTable
--
module Control.Distributed.Session.Lifted
-- | Unsession typed send
utsend :: Serializable a => ProcessId -> a -> Session s s ()
-- | Unsafe send
usend :: Serializable a => ProcessId -> a -> Session s s ()
expect :: Serializable a => Session s s a
expectTimeout :: Serializable a => Int -> Session s s (Maybe a)
newChan :: Serializable a => Session s s (SendPort a, ReceivePort a)
sendChan :: Serializable a => SendPort a -> a -> Session s s ()
receiveChan :: Serializable a => ReceivePort a -> Session s s a
receiveChanTimeout :: Serializable a => Int -> ReceivePort a -> Session s s (Maybe a)
mergePortsBiased :: Serializable a => [ReceivePort a] -> Session s s (ReceivePort a)
mergePortsRR :: Serializable a => [ReceivePort a] -> Session s s (ReceivePort a)
unsafeSend :: Serializable a => ProcessId -> a -> Session s s ()
unsafeSendChan :: Serializable a => SendPort a -> a -> Session s s ()
unsafeNSend :: Serializable a => String -> a -> Session s s ()
unsafeNSendRemote :: Serializable a => NodeId -> String -> a -> Session s s ()
receiveWait :: [Match b] -> Session s s b
receiveTimeout :: Int -> [Match b] -> Session s s (Maybe b)
unwrapMessage :: Serializable a => Message -> Session s s (Maybe a)
handleMessage :: Serializable a => Message -> (a -> Session s s b) -> Session r r (Maybe b)
handleMessage_ :: Serializable a => Message -> (a -> Session s s ()) -> Session r r ()
handleMessageP :: Serializable a => Message -> (a -> Process b) -> Session s s (Maybe b)
handleMessageP_ :: Serializable a => Message -> (a -> Process ()) -> Session s s ()
handleMessageIf :: Serializable a => Message -> (a -> Bool) -> (a -> Session s s b) -> Session r r (Maybe b)
handleMessageIf_ :: Serializable a => Message -> (a -> Bool) -> (a -> Session s s ()) -> Session r r ()
handleMessageIfP :: Serializable a => Message -> (a -> Bool) -> (a -> Process b) -> Session s s (Maybe b)
handleMessageIfP_ :: Serializable a => Message -> (a -> Bool) -> (a -> Process ()) -> Session s s ()
forward :: Message -> ProcessId -> Session s s ()
uforward :: Message -> ProcessId -> Session s s ()
delegate :: ProcessId -> (Message -> Bool) -> Session s s ()
relay :: ProcessId -> Session s s ()
proxy :: Serializable a => ProcessId -> (a -> Session s s Bool) -> Session r r ()
proxyP :: Serializable a => ProcessId -> (a -> Process Bool) -> Session s s ()
spawn :: NodeId -> Closure (SessionWrap ()) -> Session s s ProcessId
spawnP :: NodeId -> Closure (Process ()) -> Session s s ProcessId
call :: Serializable a => Static (SerializableDict a) -> NodeId -> Closure (SessionWrap a) -> Session r r a
callP :: Serializable a => Static (SerializableDict a) -> NodeId -> Closure (Process a) -> Session s s a
terminate :: Session s s a
die :: Serializable a => a -> Session s s b
kill :: ProcessId -> String -> Session s s ()
exit :: Serializable a => ProcessId -> a -> Session s s ()
catchExit :: (Show a, Serializable a) => Session s s b -> (ProcessId -> a -> Session r r b) -> Session t t b
catchExitP :: (Show a, Serializable a) => Process b -> (ProcessId -> a -> Process b) -> Session s s b
catchesExit :: Session s s b -> [ProcessId -> Message -> Session r r (Maybe b)] -> Session t t b
catchesExitP :: Process b -> [ProcessId -> Message -> Process (Maybe b)] -> Session s s b
getSelfPid :: Session s s ProcessId
getSelfNode :: Session s s NodeId
getOthPid :: Session s s (Maybe ProcessId)
getOthNode :: Session s s (Maybe NodeId)
getProcessInfo :: ProcessId -> Session s s (Maybe ProcessInfo)
getNodeStats :: NodeId -> Session s s (Either DiedReason NodeStats)
link :: ProcessId -> Session s s ()
linkNode :: NodeId -> Session s s ()
unlink :: ProcessId -> Session s s ()
unlinkNode :: NodeId -> Session s s ()
monitor :: ProcessId -> Session s s MonitorRef
monitorNode :: NodeId -> Session s s MonitorRef
monitorPort :: Serializable a => SendPort a -> Session s s MonitorRef
unmonitor :: MonitorRef -> Session s s ()
withMonitor :: ProcessId -> (MonitorRef -> Session s s a) -> Session r r a
withMonitor_ :: ProcessId -> Session s s a -> Session r r a
withMonitorP :: ProcessId -> (MonitorRef -> Process a) -> Session s s a
withMonitorP_ :: ProcessId -> Process a -> Session s s a
unStatic :: Typeable a => Static a -> Session s s a
unClosure :: Typeable a => Closure a -> Session s s a
say :: String -> Session s s ()
register :: String -> ProcessId -> Session s s ()
unregister :: String -> Session s s ()
whereis :: String -> Session s s (Maybe ProcessId)
nsend :: Serializable a => String -> a -> Session s s ()
registerRemoteAsync :: NodeId -> String -> ProcessId -> Session s s ()
reregisterRemoteAsync :: NodeId -> String -> ProcessId -> Session s s ()
whereisRemoteAsync :: NodeId -> String -> Session s s ()
nsendRemote :: Serializable a => NodeId -> String -> a -> Session s s ()
spawnAsync :: NodeId -> Closure (SessionWrap ()) -> Session r r SpawnRef
spawnAsyncP :: NodeId -> Closure (Process ()) -> Session s s SpawnRef
spawnSupervised :: NodeId -> Closure (SessionWrap ()) -> Session s s (ProcessId, MonitorRef)
spawnSupervisedP :: NodeId -> Closure (Process ()) -> Session s s (ProcessId, MonitorRef)
spawnLink :: NodeId -> Closure (SessionWrap ()) -> Session s s ProcessId
spawnLinkP :: NodeId -> Closure (Process ()) -> Session s s ProcessId
spawnMonitor :: NodeId -> Closure (SessionWrap ()) -> Session s s (ProcessId, MonitorRef)
spawnMonitorP :: NodeId -> Closure (Process ()) -> Session s s (ProcessId, MonitorRef)
spawnChannel :: Serializable a => Static (SerializableDict a) -> NodeId -> Closure (ReceivePort a -> SessionWrap ()) -> Session s s (SendPort a)
spawnChannelP :: Serializable a => Static (SerializableDict a) -> NodeId -> Closure (ReceivePort a -> Process ()) -> Session s s (SendPort a)
spawnLocal :: Session s s () -> Session r r ProcessId
spawnLocalP :: Process () -> Session s s ProcessId
spawnChannelLocal :: Serializable a => (ReceivePort a -> Session s s ()) -> Session r r (SendPort a)
spawnChannelLocalP :: Serializable a => (ReceivePort a -> Process ()) -> Session s s (SendPort a)
callLocal :: Session s s a -> Session s s a
callLocalP :: Process a -> Session s s a
reconnect :: ProcessId -> Session s s ()
reconnectPort :: SendPort a -> Session s s ()
-- | Defines several combinators for spawning sessions
--
-- Here we define a session to be two dual Sessions that together
-- implement a protocol described by a session type.
--
-- The following shows an example of how to spawn a session
--
--
-- {-# LANGUAGE TemplateHaskell #-}
-- {-# LANGUAGE DataKinds #-}
-- {-# LANGUAGE TypeOperators #-}
--
-- import qualified SessionTypes.Indexed as I
-- import Control.Distributed.Session hiding (getSelfPid, expect)
-- import Control.Distributed.Process (liftIO, Process, RemoteTable, NodeId, getSelfPid, ProcessId, expect)
-- import Control.Distributed.Process.Closure (remotable, mkClosure)
-- import Control.Distributed.Process.Node
-- import Network.Transport.TCP
--
-- sess1 :: Session ('Cap '[] (Int :!> Eps)) ('Cap '[] Eps) ()
-- sess1 = send 5 I.>> eps ()
--
-- sess2 :: ProcessId -> Session ('Cap '[] (Int :?> Eps)) ('Cap '[] Eps) ()
-- sess2 pid = recv I.>>= x -> utsend pid x I.>>= eps
--
-- spawnSess :: ProcessId -> SpawnSession () ()
-- spawnSess pid = SpawnSession sess1 (sess2 pid)
--
-- remotable ['spawnSess]
--
-- p1 :: NodeId -> Process ()
-- p1 nid = do
-- pid <- getSelfPid
-- spawnRRSessionP nid nid ($(mkClosure 'spawnSess) pid)
-- a <- expect :: Process Int
-- liftIO (putStrLn $ show a)
--
-- myRemoteTable :: RemoteTable
-- myRemoteTable = Main.__remoteTable $ sessionRemoteTable initRemoteTable
--
-- main :: IO ()
-- main = do
-- Right t <- createTransport "127.0.0.1" "100000" defaultTCPParameters
-- node <- newLocalNode t myRemoteTable
-- runProcess node $ p1 (localNodeId node)
--
--
--
-- >>> main
-- > 5
--
--
-- In p1 we spawn a session that consists of two Sessions that are
-- remotely spawned (which happens to be the local node).
--
-- We do so using the spawnRRSessionP function that we can call
-- within a Process. We pass it the two node identifiers followed
-- by a closure that takes an argument.
--
-- Sess1 and sess2 implement both sides of the protocol. We can insert
-- these into a SpawnSession, because they are dual to each other.
--
--
-- spawnSess :: ProcessId -> SpawnSession () ()
-- spawnSess pid = SpawnSession sess1 (sess2 pid)
--
--
-- Then to create a closure for spawnSess that we can then pass
-- to spawnRRSessionP we first add spawnSess to the
-- remotable of the current module.
--
--
-- remotable ['spawnSess]
--
--
-- remotable is a top-level Template Haskell splice that creates a
-- closure function for us.
--
-- To use this closure function we can simply do
--
--
-- $(mkClosure 'spawnSess) pid
--
--
-- We use mkClosure such that we can still pass an argument to
-- spawnSess with the result being of type Closure (SpawnSession () ())
--
-- It is important that the node that we run p1 on knows how to evaluate
-- a closure of type Closure (SpawnSession () ()). This requires that we
-- compose the initRemoteTable of a node with the remotable of this
-- module.
--
-- Within spawnRRSessionP we make use of internally defined
-- closures. The library therefore exports sessionRemoteTable that
-- should always be passed to a node if you make use of a function within
-- this library that takes a closure as an argument.
--
--
-- myRemoteTable :: RemoteTable
-- myRemoteTable = Main.__remoteTable $ sessionRemoteTable initRemoteTable
--
--
--
-- node <- newLocalNode t myRemoteTable
--
module Control.Distributed.Session.Spawn
-- | Calls a local session consisting of two dual Sessions.
--
-- Spawns a new local process for the second Session and runs the
-- first Session on the current process.
--
-- Returns the result of the first Session and the
-- ProcessId of the second Session.
callLocalSessionP :: (HasConstraint Serializable s, HasConstraint Serializable (Dual s)) => Session s r a -> Session (Dual s) r b -> Process (a, ProcessId)
-- | Sessioned version of callLocalSessionP
callLocalSession :: (HasConstraint Serializable s, HasConstraint Serializable (Dual s)) => Session s r a -> Session (Dual s) r b -> Session k k (a, ProcessId)
-- | Calls a remote session consisting of two dual Sessions.
--
-- Spawns a remote process for the second Session and runs the
-- first Session on the current process.
--
-- Returns the result of the frist Session and the
-- ProcessId of the second Session.
--
-- The arguments of this function are described as follows:
--
--
-- - Static (SerializableDict a): Describes how to serialize a value of
-- type a
-- - NodeId: The node identifier of the node that the second
-- Session should be spawned to.
-- - Closure (SpawnSession a ()): A closure of a wrapper over two dual
-- Sessions.
--
--
-- Requires sessionRemoteTable
callRemoteSessionP :: Serializable a => Static (SerializableDict a) -> NodeId -> Closure (SpawnSession a ()) -> Process (a, ProcessId)
-- | Sessioned version of callRemoteSession
--
-- Requires sessionRemoteTable
callRemoteSession :: Serializable a => Static (SerializableDict a) -> NodeId -> Closure (SpawnSession a ()) -> Session k k (a, ProcessId)
-- | Same as callRemoteSessionP, but we no longer need to provide a
-- static serializable dictionary, because the result type of the first
-- session is unit.
--
-- Requires sessionRemoteTable
callRemoteSessionP' :: NodeId -> Closure (SpawnSession () ()) -> Process (ProcessId)
-- | Sessioned version of callRemoteSessionP'
--
-- Requires sessionRemoteTable
callRemoteSession' :: NodeId -> Closure (SpawnSession () ()) -> Session s s (ProcessId)
-- | Spawns a local session.
--
-- Both Sessions are spawned locally.
--
-- Returns the ProcessId of both spawned processes.
spawnLLSessionP :: (HasConstraint Serializable s, HasConstraint Serializable (Dual s)) => Session s r a -> Session (Dual s) r b -> Process (ProcessId, ProcessId)
-- | Sessioned version of spawnLLSession
spawnLLSession :: (HasConstraint Serializable s, HasConstraint Serializable (Dual s)) => Session s r a -> Session (Dual s) r b -> Session t t (ProcessId, ProcessId)
-- | Spawns one Session local and spawns another Session
-- remote.
--
-- Returns the ProcessId of both spawned processes.
--
-- The arguments are described as follows:
--
--
-- - NodeId: The node identifier of the node that the second
-- Session should be spawned to.
-- - Closure (SpawnSession () ()): A closure of a wrapper over two dual
-- Sessions.
--
--
-- Requires sessionRemoteTable
spawnLRSessionP :: NodeId -> Closure (SpawnSession () ()) -> Process (ProcessId, ProcessId)
-- | Sessioned version of spawnLRSessionP
--
-- Requires sessionRemoteTable
spawnLRSession :: NodeId -> Closure (SpawnSession () ()) -> Session s s (ProcessId, ProcessId)
-- | Spawns a remote session. Both Session arguments are spawned
-- remote.
--
-- Returns the ProcessId of both spawned processes.
--
-- The arguments are described as follows:
--
--
-- - NodeId: The node identifier of the node that the first
-- Session should be spawned to.
-- - NodeId: The node identifier of the node that the second
-- Session should be spawned to.
-- - Closure (SpawnSession () ()): A closure of a wrapper over two dual
-- Sessions.
--
--
-- Requires sessionRemoteTable
spawnRRSessionP :: NodeId -> NodeId -> Closure (SpawnSession () ()) -> Process (ProcessId, ProcessId)
-- | Sessioned version of SpawnRRSession
--
-- Requires sessionRemoteTable
spawnRRSession :: NodeId -> NodeId -> Closure (SpawnSession () ()) -> Session s s (ProcessId, ProcessId)
-- | This package defines a wrapper over the sessiontypes library that
-- allows for evaluating session typed programs to Cloud Haskell
-- programs.
--
-- The goal of this library is to allow a user to define two dual session
-- typed programs, spawn two processes and have these processes evaluate
-- the programs.
--
-- Session types guarantee that the resulting Cloud Haskell programs
-- correctly implement the protocol and that they are non-deadlocking.
--
-- We define a session typed program with an indexed monad Session
-- that is both a reader monad and a wrapper over a STTerm that
-- uses Process as its underlying monad.
--
-- This module exports the most important parts of this library:
--
--
--
-- Additionally we defined wrappers for using the interpreters defined in
-- the sessiontypes package on a Session:
--
--
module Control.Distributed.Session
-- | Session is defined as a newtype wrapper over a function that
-- takes a `Maybe SessionInfo` and returns an indexed codensity monad
-- transformer over the Process monad.
--
-- Session is also a reader monad that has a Maybe SessionInfo as
-- its environment. SessionInfo is wrapped in a Maybe,
-- because we also allow a session to be run singularly. In which case
-- there is no other Session to communicate with and therefore is there
-- also no need for a SessionInfo.
--
-- The function returns the indexed codensity monad and not simply a
-- STTerm, because from benchmarking the codensity monad gave us
-- significant performance improvements for free.
newtype Session s r a
Session :: (Maybe SessionInfo -> IxC Process s r a) -> Session s r a
[runSessionC] :: Session s r a -> Maybe SessionInfo -> IxC Process s r a
-- | The SessionInfo data type tells us information about another
-- Session. Namely, the Session that is in a session with
-- the Session that this specific SessionInfo belongs to.
data SessionInfo
SessionInfo :: ProcessId -> NodeId -> UTChan -> SessionInfo
-- | The ProcessId of the dual Session
[othPid] :: SessionInfo -> ProcessId
-- | The NodeId of the Node that the dual Session
-- runs on
[othNode] :: SessionInfo -> NodeId
-- | A send port belonging to the dual Session, such that we can
-- send messages to it. And a receive port of which the dual
-- Session has its send port, such that we can receive messages
-- from the dual Session.
[utchan] :: SessionInfo -> UTChan
-- | Evaluates a session to a STTerm
runSession :: Session s r a -> Maybe SessionInfo -> STTerm Process s r a
-- | Lifts a Process computation
liftP :: Process a -> Session s s a
-- | Lifts a STTerm computation
liftST :: STTerm Process s r a -> Session s r a
-- | Calls a local session consisting of two dual Sessions.
--
-- Spawns a new local process for the second Session and runs the
-- first Session on the current process.
--
-- Returns the result of the first Session and the
-- ProcessId of the second Session.
callLocalSessionP :: (HasConstraint Serializable s, HasConstraint Serializable (Dual s)) => Session s r a -> Session (Dual s) r b -> Process (a, ProcessId)
-- | Sessioned version of callLocalSessionP
callLocalSession :: (HasConstraint Serializable s, HasConstraint Serializable (Dual s)) => Session s r a -> Session (Dual s) r b -> Session k k (a, ProcessId)
-- | Calls a remote session consisting of two dual Sessions.
--
-- Spawns a remote process for the second Session and runs the
-- first Session on the current process.
--
-- Returns the result of the frist Session and the
-- ProcessId of the second Session.
--
-- The arguments of this function are described as follows:
--
--
-- - Static (SerializableDict a): Describes how to serialize a value of
-- type a
-- - NodeId: The node identifier of the node that the second
-- Session should be spawned to.
-- - Closure (SpawnSession a ()): A closure of a wrapper over two dual
-- Sessions.
--
--
-- Requires sessionRemoteTable
callRemoteSessionP :: Serializable a => Static (SerializableDict a) -> NodeId -> Closure (SpawnSession a ()) -> Process (a, ProcessId)
-- | Sessioned version of callRemoteSession
--
-- Requires sessionRemoteTable
callRemoteSession :: Serializable a => Static (SerializableDict a) -> NodeId -> Closure (SpawnSession a ()) -> Session k k (a, ProcessId)
-- | Same as callRemoteSessionP, but we no longer need to provide a
-- static serializable dictionary, because the result type of the first
-- session is unit.
--
-- Requires sessionRemoteTable
callRemoteSessionP' :: NodeId -> Closure (SpawnSession () ()) -> Process (ProcessId)
-- | Sessioned version of callRemoteSessionP'
--
-- Requires sessionRemoteTable
callRemoteSession' :: NodeId -> Closure (SpawnSession () ()) -> Session s s (ProcessId)
-- | Spawns a local session.
--
-- Both Sessions are spawned locally.
--
-- Returns the ProcessId of both spawned processes.
spawnLLSessionP :: (HasConstraint Serializable s, HasConstraint Serializable (Dual s)) => Session s r a -> Session (Dual s) r b -> Process (ProcessId, ProcessId)
-- | Sessioned version of spawnLLSession
spawnLLSession :: (HasConstraint Serializable s, HasConstraint Serializable (Dual s)) => Session s r a -> Session (Dual s) r b -> Session t t (ProcessId, ProcessId)
-- | Spawns one Session local and spawns another Session
-- remote.
--
-- Returns the ProcessId of both spawned processes.
--
-- The arguments are described as follows:
--
--
-- - NodeId: The node identifier of the node that the second
-- Session should be spawned to.
-- - Closure (SpawnSession () ()): A closure of a wrapper over two dual
-- Sessions.
--
--
-- Requires sessionRemoteTable
spawnLRSessionP :: NodeId -> Closure (SpawnSession () ()) -> Process (ProcessId, ProcessId)
-- | Sessioned version of spawnLRSessionP
--
-- Requires sessionRemoteTable
spawnLRSession :: NodeId -> Closure (SpawnSession () ()) -> Session s s (ProcessId, ProcessId)
-- | Spawns a remote session. Both Session arguments are spawned
-- remote.
--
-- Returns the ProcessId of both spawned processes.
--
-- The arguments are described as follows:
--
--
-- - NodeId: The node identifier of the node that the first
-- Session should be spawned to.
-- - NodeId: The node identifier of the node that the second
-- Session should be spawned to.
-- - Closure (SpawnSession () ()): A closure of a wrapper over two dual
-- Sessions.
--
--
-- Requires sessionRemoteTable
spawnRRSessionP :: NodeId -> NodeId -> Closure (SpawnSession () ()) -> Process (ProcessId, ProcessId)
-- | Sessioned version of SpawnRRSession
--
-- Requires sessionRemoteTable
spawnRRSession :: NodeId -> NodeId -> Closure (SpawnSession () ()) -> Session s s (ProcessId, ProcessId)
-- | This function unpacks a Session to a STTerm using a
-- given SessionInfo.
--
-- It then evaluates the STTerm by mapping Cloud Haskell semantics
-- to each constructor of STTerm.
--
-- The function relies on that there exists another session (on a
-- different process) that is also being evaluated (using evalSession)
-- and acts as the dual the session that function is now evaluating.
--
-- The underlying communication method is a session typed channel
-- (STChannelT). There should be no interference from other
-- processes, unless you go through the effort of sharing the send port.
evalSession :: forall s r a. HasConstraint Serializable s => Session s r a -> SessionInfo -> Process a
-- | Similar to evalSession, except for that it does not evaluate
-- session typed actions.
--
-- Only returns and lifted computations are evaluated. This also means
-- that there does not need to be a dual session that is evaluated on a
-- different process.
--
-- It also assumes that SessionInfo is not used. Use
-- evalSessionEq' if this is not the case.
evalSessionEq :: Session s s a -> Process a
-- | Same as evalSessionEq, but you may now provide a
-- SessionInfo.
evalSessionEq' :: Session s s a -> SessionInfo -> Process a
-- | Data type that encapsulates two sessions for the purpose of remotely
-- spawning them
--
-- The session types of the sessions are existentially quantified, but we
-- still ensure duality and constrain them properly, such that they can
-- be passed to evalSession.
data SpawnSession a b
[SpawnSession] :: (HasConstraintST Serializable s, HasConstraintST Serializable (DualST s), Typeable a, Typeable b) => Session ( 'Cap '[] s) r a -> Session ( 'Cap '[] (DualST s)) r b -> SpawnSession a b
-- | Data type that encapsulates a single session performing no session
-- typed action that can be remotely spawned.
--
-- We use this data type mostly for convenience in combination with
-- evalSessionEq allowing us to avoid the Serializable
-- constraint.
data SessionWrap a
[SessionWrap] :: Session s s a -> SessionWrap a
-- | RemoteTable that binds all in this module defined static functions to
-- their corresponding evaluation functions.
sessionRemoteTable :: RemoteTable -> RemoteTable
-- | Static function for remotely spawning a single session
--
-- When remotely spawning any session we must always pass it the
-- ProcessId and NodeId of the spawning process.
--
-- We must pass a Closure of a SessionWrap instead of just a
-- SessionWrap, because that would require serializing a
-- SessionWrap which is not possible.
--
-- Furthermore, we must also pass a SerializableDict that shows
-- how to serialize a value of type a.
remoteSessionStatic :: Static (SerializableDict a -> Closure (SessionWrap a) -> Process a)
-- | Closure function for remotely spawning a single session
remoteSessionClosure :: Static (SerializableDict a) -> Closure (SessionWrap a) -> Closure (Process a)
-- | Same as remoteSessionStatic, except that we do not need to
-- provide a SerializableDict.
remoteSessionStatic' :: Static (Closure (SessionWrap ()) -> Process ())
-- | Same as remoteSessionClosure, except that we do not need to
-- provide a SerializableDict.
remoteSessionClosure' :: Closure (SessionWrap ()) -> Closure (Process ())
-- | A static function specific to the lifted spawnChannel function
-- that can be found in Control.Distributed.Session.Lifted
spawnChannelStatic :: Static (SerializableDict a -> Closure (ReceivePort a -> SessionWrap ()) -> ReceivePort a -> Process ())
-- | A closure specific to the lifted spawnChannel function that can
-- be found in Control.Distributed.Session.Lifted
spawnChannelClosure :: Static (SerializableDict a) -> Closure (ReceivePort a -> SessionWrap ()) -> Closure (ReceivePort a -> Process ())
-- | Function that evalutes the first argument of a SpawnSession in
-- a local manner.
--
-- It is local in that we do not create an accompanying closure.
evalLocalSession :: Typeable a => (ProcessId, NodeId, Closure (SpawnSession a ())) -> Process a
-- | Static function for remotely evaluating the second argument of a
-- SpawnSession.
--
-- This function works dually to evalLocalSession.
remoteSpawnSessionStatic :: Static (SerializableDict a -> (ProcessId, NodeId, Closure (SpawnSession a ())) -> Process ())
-- | Closure for remotely evaluating the second argument of a
-- SpawnSession
remoteSpawnSessionClosure :: Static (SerializableDict a) -> (ProcessId, NodeId, Closure (SpawnSession a ())) -> Closure (Process ())
-- | Same as remoteSpawnSessionStatic, except for that we do not
-- need to provide a SerializableDict.
remoteSpawnSessionStatic' :: Static ((ProcessId, NodeId, Closure (SpawnSession () ())) -> Process ())
-- | Same as remoteSpawnSessionClosure, except for that we do not
-- need to provide a SerializableDict.
remoteSpawnSessionClosure' :: (ProcessId, NodeId, Closure (SpawnSession () ())) -> Closure (Process ())
-- | Static function for remotely evaluating the second argument of a
-- SpawnSession
--
-- This function is very similar to remoteSpawnSessionStatic'. The
-- difference is that this function assumes that the other session was
-- also remotely spawned.
--
-- Therefore we require an extra send of the ProcessId of the to
-- be spawned process.
rrSpawnSessionSendStatic :: Static ((ProcessId, NodeId, Closure (SpawnSession () ())) -> Process ())
-- | Closure for remotely evaluating the second argument of a
-- SpawnSession.
rrSpawnSessionSendClosure :: (ProcessId, NodeId, Closure (SpawnSession () ())) -> Closure (Process ())
-- | Closure for remotely evaluating the first argument of a
-- SpawnSession
--
-- This function acts dual to rrSpawnSessionSend and assumes that
-- it will first receive a ProcessId.
rrSpawnSessionExpectStatic :: Static ((NodeId, Closure (SpawnSession () ())) -> Process ())
-- | Closure for remotely evaluating the first argument of a
-- SpawnSession.
rrSpawnSessionExpectClosure :: (NodeId, Closure (SpawnSession () ())) -> Closure (Process ())
-- | Basic message type that existentially quantifies the content of the
-- message
data Message
Message :: a -> Message
-- | Session typed send port as a wrapper over SendPort Message. It is
-- parameterized with a capability/sessiontype.
data STSendPort (l :: Cap Type)
STSendPort :: (SendPort Message) -> STSendPort
-- | Session typed receive port as a wrapper over ReceivePort Message. It
-- is parameterized with a capability/sessiontype.
data STReceivePort (l :: Cap Type)
STReceivePort :: (ReceivePort Message) -> STReceivePort
-- | Type synonym for a session typed channel given a single session type
--
-- This removes recv session types from the given session type as it is
-- passed to the send port type
--
-- Also removes send session types from the given session type as it is
-- passed to the receive port type
type STChan s = (STSendPort (RemoveRecv s), STReceivePort (RemoveSend s))
-- | Same as STChan, but it is given a session type for the send
-- port type and a separate session type for the receive port type
type STChanBi s r = (STSendPort (RemoveRecv s), STReceivePort (RemoveSend r))
-- | Unsession typed typed channel
--
-- It is essentially just a typed channel that is parameterized with
-- Message.
--
-- We can carry around this type in Session, but not a
-- STChan.
type UTChan = (SendPort Message, ReceivePort Message)
-- | Creates a new session typed channel given a single session type
newSTChan :: Proxy s -> Process (STChan s)
-- | Creates a new session typed channel given separate session types for
-- the send port and receive port
newSTChanBi :: Proxy s -> Proxy r -> Process (STChanBi s r)
-- | Creates an unsession typed channel
newUTChan :: Process UTChan
-- | Converts an unsession typed channel to a session typed channel
toSTChan :: UTChan -> Proxy s -> STChan s
-- | Converts an unsession typed channel to a session typed channel
toSTChanBi :: UTChan -> Proxy s -> Proxy r -> STChanBi s r
-- | Converts a session typed send port into a Proxy
sendProxy :: STSendPort s -> Proxy s
-- | Converts a session typed receive port into a Proxy
recvProxy :: STReceivePort s -> Proxy s
-- | Sends a message using a session typed send port
sendSTChan :: Serializable a => STSendPort ( 'Cap ctx (a :!> l)) -> a -> Process (STSendPort ( 'Cap ctx l))
-- | Receives a message using a session typed receive port
recvSTChan :: Serializable a => STReceivePort ( 'Cap ctx (a :?> l)) -> Process (a, STReceivePort ( 'Cap ctx l))
-- | Type class that defines combinators for branching on a session typed
-- port
class STSplit (m :: Cap Type -> Type)
-- | select the first branch of a selection using the given port
sel1Chan :: STSplit m => m ( 'Cap ctx (Sel (s : xs))) -> m ( 'Cap ctx s)
-- | select the second branch of a selection using the given port
sel2Chan :: STSplit m => m ( 'Cap ctx (Sel (s : (t : xs)))) -> m ( 'Cap ctx (Sel (t : xs)))
-- | select the first branch of an offering using the given port
off1Chan :: STSplit m => m ( 'Cap ctx (Off (s : xs))) -> m ( 'Cap ctx s)
-- | select the second branch of an offering using the given port
off2Chan :: STSplit m => m ( 'Cap ctx (Off (s : (t : xs)))) -> m ( 'Cap ctx (Off (t : xs)))
-- | Type class for recursion on a session typed port
class STRec (m :: Cap Type -> Type)
recChan :: STRec m => m ( 'Cap ctx (R s)) -> m ( 'Cap (s : ctx) s)
wkChan :: STRec m => m ( 'Cap (t : ctx) (Wk s)) -> m ( 'Cap ctx s)
varChan :: STRec m => m ( 'Cap (s : ctx) V) -> m ( 'Cap (s : ctx) s)
-- | Indexed monad transformer that is indexed by two products of session
-- types
--
-- This monad also acts as a state monad that whose state is defined by a
-- session typed channel and dependent on the indexing of the monad.
data STChannelT m (p :: Prod Type) (q :: Prod Type) a
STChannelT :: ((STSendPort (Left p), STReceivePort (Right p)) -> m (a, (STSendPort (Left q), STReceivePort (Right q)))) -> STChannelT m a
[runSTChannelT] :: STChannelT m a -> ((STSendPort (Left p), STReceivePort (Right p)) -> m (a, (STSendPort (Left q), STReceivePort (Right q))))
-- | Send a message
--
-- Only the session type of the send port needs to be adjusted
sendSTChanM :: Serializable a => a -> STChannelT Process ( 'Cap ctx (a :!> l) :*: r) ( 'Cap ctx l :*: r) ()
-- | receive a message
--
-- Only the session type of the receive port needs to be adjusted
recvSTChanM :: Serializable a => STChannelT Process (l :*: ( 'Cap ctx (a :?> r))) (l :*: 'Cap ctx r) a
-- | select the first branch of a selection
--
-- Both ports are now adjusted. This is similarly so for the remaining
-- combinators.
sel1ChanM :: STChannelT Process ( 'Cap lctx (Sel (l : ls)) :*: ( 'Cap rctx (Sel (r : rs)))) ( 'Cap lctx l :*: 'Cap rctx r) ()
-- | select the second branch of a selection
sel2ChanM :: STChannelT Process ( 'Cap lctx (Sel (s1 : (t1 : xs1))) :*: 'Cap rctx (Sel (s2 : (t2 : xs2)))) ( 'Cap lctx (Sel (t1 : xs1)) :*: 'Cap rctx (Sel (t2 : xs2))) ()
-- | select the first branch of an offering
off1ChanM :: STChannelT Process ( 'Cap lctx (Off (l : ls)) :*: ( 'Cap rctx (Off (r : rs)))) ( 'Cap lctx l :*: 'Cap rctx r) ()
-- | select the second branch of an offering
off2ChanM :: STChannelT Process ( 'Cap lctx (Off (s1 : (t1 : xs1))) :*: 'Cap rctx (Off (s2 : (t2 : xs2)))) ( 'Cap lctx (Off (t1 : xs1)) :*: 'Cap rctx (Off (t2 : xs2))) ()
-- | delimit scope of recursion
recChanM :: STChannelT Process ( 'Cap sctx (R s) :*: 'Cap rctx (R r)) ( 'Cap (s : sctx) s :*: 'Cap (r : rctx) r) ()
-- | weaken scope of recursion
wkChanM :: STChannelT Process ( 'Cap (t : sctx) (Wk s) :*: 'Cap (k : rctx) (Wk r)) ( 'Cap sctx s :*: 'Cap rctx r) ()
-- | recursion variable (recurse here)
varChanM :: STChannelT Process (( 'Cap (s : sctx) V) :*: ( 'Cap (r : rctx) V)) ( 'Cap (s : sctx) s :*: 'Cap (r : rctx) r) ()
-- | ports are no longer usable
epsChanM :: STChannelT Process ( 'Cap ctx Eps :*: 'Cap ctx Eps) ( 'Cap ctx Eps :*: 'Cap ctx Eps) ()
-- | Unsession typed send
utsend :: Serializable a => ProcessId -> a -> Session s s ()
-- | Unsafe send
usend :: Serializable a => ProcessId -> a -> Session s s ()
expect :: Serializable a => Session s s a
expectTimeout :: Serializable a => Int -> Session s s (Maybe a)
newChan :: Serializable a => Session s s (SendPort a, ReceivePort a)
sendChan :: Serializable a => SendPort a -> a -> Session s s ()
receiveChan :: Serializable a => ReceivePort a -> Session s s a
receiveChanTimeout :: Serializable a => Int -> ReceivePort a -> Session s s (Maybe a)
mergePortsBiased :: Serializable a => [ReceivePort a] -> Session s s (ReceivePort a)
mergePortsRR :: Serializable a => [ReceivePort a] -> Session s s (ReceivePort a)
unsafeSend :: Serializable a => ProcessId -> a -> Session s s ()
unsafeSendChan :: Serializable a => SendPort a -> a -> Session s s ()
unsafeNSend :: Serializable a => String -> a -> Session s s ()
unsafeNSendRemote :: Serializable a => NodeId -> String -> a -> Session s s ()
receiveWait :: [Match b] -> Session s s b
receiveTimeout :: Int -> [Match b] -> Session s s (Maybe b)
unwrapMessage :: Serializable a => Message -> Session s s (Maybe a)
handleMessage :: Serializable a => Message -> (a -> Session s s b) -> Session r r (Maybe b)
handleMessage_ :: Serializable a => Message -> (a -> Session s s ()) -> Session r r ()
handleMessageP :: Serializable a => Message -> (a -> Process b) -> Session s s (Maybe b)
handleMessageP_ :: Serializable a => Message -> (a -> Process ()) -> Session s s ()
handleMessageIf :: Serializable a => Message -> (a -> Bool) -> (a -> Session s s b) -> Session r r (Maybe b)
handleMessageIf_ :: Serializable a => Message -> (a -> Bool) -> (a -> Session s s ()) -> Session r r ()
handleMessageIfP :: Serializable a => Message -> (a -> Bool) -> (a -> Process b) -> Session s s (Maybe b)
handleMessageIfP_ :: Serializable a => Message -> (a -> Bool) -> (a -> Process ()) -> Session s s ()
forward :: Message -> ProcessId -> Session s s ()
uforward :: Message -> ProcessId -> Session s s ()
delegate :: ProcessId -> (Message -> Bool) -> Session s s ()
relay :: ProcessId -> Session s s ()
proxy :: Serializable a => ProcessId -> (a -> Session s s Bool) -> Session r r ()
proxyP :: Serializable a => ProcessId -> (a -> Process Bool) -> Session s s ()
spawn :: NodeId -> Closure (SessionWrap ()) -> Session s s ProcessId
spawnP :: NodeId -> Closure (Process ()) -> Session s s ProcessId
call :: Serializable a => Static (SerializableDict a) -> NodeId -> Closure (SessionWrap a) -> Session r r a
callP :: Serializable a => Static (SerializableDict a) -> NodeId -> Closure (Process a) -> Session s s a
terminate :: Session s s a
die :: Serializable a => a -> Session s s b
kill :: ProcessId -> String -> Session s s ()
exit :: Serializable a => ProcessId -> a -> Session s s ()
catchExit :: (Show a, Serializable a) => Session s s b -> (ProcessId -> a -> Session r r b) -> Session t t b
catchExitP :: (Show a, Serializable a) => Process b -> (ProcessId -> a -> Process b) -> Session s s b
catchesExit :: Session s s b -> [ProcessId -> Message -> Session r r (Maybe b)] -> Session t t b
catchesExitP :: Process b -> [ProcessId -> Message -> Process (Maybe b)] -> Session s s b
getSelfPid :: Session s s ProcessId
getSelfNode :: Session s s NodeId
getOthPid :: Session s s (Maybe ProcessId)
getOthNode :: Session s s (Maybe NodeId)
getProcessInfo :: ProcessId -> Session s s (Maybe ProcessInfo)
getNodeStats :: NodeId -> Session s s (Either DiedReason NodeStats)
link :: ProcessId -> Session s s ()
linkNode :: NodeId -> Session s s ()
unlink :: ProcessId -> Session s s ()
unlinkNode :: NodeId -> Session s s ()
monitor :: ProcessId -> Session s s MonitorRef
monitorNode :: NodeId -> Session s s MonitorRef
monitorPort :: Serializable a => SendPort a -> Session s s MonitorRef
unmonitor :: MonitorRef -> Session s s ()
withMonitor :: ProcessId -> (MonitorRef -> Session s s a) -> Session r r a
withMonitor_ :: ProcessId -> Session s s a -> Session r r a
withMonitorP :: ProcessId -> (MonitorRef -> Process a) -> Session s s a
withMonitorP_ :: ProcessId -> Process a -> Session s s a
unStatic :: Typeable a => Static a -> Session s s a
unClosure :: Typeable a => Closure a -> Session s s a
say :: String -> Session s s ()
register :: String -> ProcessId -> Session s s ()
unregister :: String -> Session s s ()
whereis :: String -> Session s s (Maybe ProcessId)
nsend :: Serializable a => String -> a -> Session s s ()
registerRemoteAsync :: NodeId -> String -> ProcessId -> Session s s ()
reregisterRemoteAsync :: NodeId -> String -> ProcessId -> Session s s ()
whereisRemoteAsync :: NodeId -> String -> Session s s ()
nsendRemote :: Serializable a => NodeId -> String -> a -> Session s s ()
spawnAsync :: NodeId -> Closure (SessionWrap ()) -> Session r r SpawnRef
spawnAsyncP :: NodeId -> Closure (Process ()) -> Session s s SpawnRef
spawnSupervised :: NodeId -> Closure (SessionWrap ()) -> Session s s (ProcessId, MonitorRef)
spawnSupervisedP :: NodeId -> Closure (Process ()) -> Session s s (ProcessId, MonitorRef)
spawnLink :: NodeId -> Closure (SessionWrap ()) -> Session s s ProcessId
spawnLinkP :: NodeId -> Closure (Process ()) -> Session s s ProcessId
spawnMonitor :: NodeId -> Closure (SessionWrap ()) -> Session s s (ProcessId, MonitorRef)
spawnMonitorP :: NodeId -> Closure (Process ()) -> Session s s (ProcessId, MonitorRef)
spawnChannel :: Serializable a => Static (SerializableDict a) -> NodeId -> Closure (ReceivePort a -> SessionWrap ()) -> Session s s (SendPort a)
spawnChannelP :: Serializable a => Static (SerializableDict a) -> NodeId -> Closure (ReceivePort a -> Process ()) -> Session s s (SendPort a)
spawnLocal :: Session s s () -> Session r r ProcessId
spawnLocalP :: Process () -> Session s s ProcessId
spawnChannelLocal :: Serializable a => (ReceivePort a -> Session s s ()) -> Session r r (SendPort a)
spawnChannelLocalP :: Serializable a => (ReceivePort a -> Process ()) -> Session s s (SendPort a)
callLocal :: Session s s a -> Session s s a
callLocalP :: Process a -> Session s s a
reconnect :: ProcessId -> Session s s ()
reconnectPort :: SendPort a -> Session s s ()
module Control.Distributed.Session.Visualize
-- | Visualizes the session type of a given STTerm You may use
-- this function in the following way
--
--
-- main = visualize st
--
--
-- Then the following command will generate a diagram named
-- "sessiontype.png"
--
--
-- stack exec vis-sessiontype -- -o sessiontype.png -w 400
--
--
-- For more information on how to generate a diagram please visit the
-- diagrams package
visualize :: (MonadSession m, MkDiagram * s) => m Cap * ctx s r a -> IO ()
-- | Visualizes a given session type denoted by a Proxy.
visualizeP :: MkDiagram k s => Proxy ST k s -> IO ()