sessiontypes-distributed-0.1.1: Session types distributed

Safe HaskellNone
LanguageHaskell2010

Control.Distributed.Session.Spawn

Contents

Description

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

Synopsis

Call

callLocalSessionP :: (HasConstraint Serializable s, HasConstraint Serializable (Dual s)) => Session s r a -> Session (Dual s) r b -> Process (a, ProcessId) Source #

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.

callRemoteSessionP :: Serializable a => Static (SerializableDict a) -> NodeId -> Closure (SpawnSession a ()) -> Process (a, ProcessId) Source #

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' :: NodeId -> Closure (SpawnSession () ()) -> Process ProcessId Source #

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

Spawn

spawnLLSessionP :: (HasConstraint Serializable s, HasConstraint Serializable (Dual s)) => Session s r a -> Session (Dual s) r b -> Process (ProcessId, ProcessId) Source #

Spawns a local session.

Both Sessions are spawned locally.

Returns the ProcessId of both spawned processes.

spawnLRSessionP :: NodeId -> Closure (SpawnSession () ()) -> Process (ProcessId, ProcessId) Source #

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

spawnRRSessionP :: NodeId -> NodeId -> Closure (SpawnSession () ()) -> Process (ProcessId, ProcessId) Source #

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

spawnRRSession :: NodeId -> NodeId -> Closure (SpawnSession () ()) -> Session s s (ProcessId, ProcessId) Source #

Sessioned version of SpawnRRSession

Requires sessionRemoteTable