sessiontypes-distributed-0.1.0: src/Control/Distributed/Session/Session.hs
{-# LANGUAGE RebindableSyntax #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
-- | This module defines the `Session` session typed indexed monad.
module Control.Distributed.Session.Session (
-- * Data types
Session(..),
SessionInfo(..),
runSession,
-- * Lifting
liftP,
liftST
) where
import Control.SessionTypes
import Control.SessionTypes.Codensity
import Control.SessionTypes.Indexed hiding (abs)
import Control.Distributed.Session.STChannel (UTChan)
import Control.Distributed.Process as P (Process, ProcessId, NodeId, liftIO)
-- | `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 { runSessionC :: 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 {
othPid :: ProcessId, -- ^ The `ProcessId` of the dual `Session`
othNode :: NodeId, -- ^ The `NodeId` of the `Node` that the dual `Session` runs on
utchan :: UTChan -- ^ 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`.
}
-- | Evaluates a session to a `STTerm`
runSession :: Session s r a -> Maybe SessionInfo -> STTerm Process s r a
runSession (Session c) si = abs $ c si
instance IxFunctor Session where
fmap f sess = Session $ \si -> fmap f $ runSessionC sess si
instance IxApplicative Session where
pure = return
f <*> g = Session $ \si -> (runSessionC f si) <*> (runSessionC g si)
instance IxMonad Session where
return a = Session $ \_ -> return a
(Session s) >>= f = Session $ \si -> do
a <- s si
let (Session r) = f a
r si
instance MonadSession Session where
send a = Session $ const $ send a
recv = Session $ const recv
sel1 = Session $ const sel1
sel2 = Session $ const sel2
offZ (Session f) = Session $ offZ . f
offS (Session f) (Session g) = Session $ \si -> offS (f si) (g si)
recurse (Session f) = Session $ \si -> recurse (f si)
weaken (Session f) = Session $ \si -> weaken (f si)
var (Session f) = Session $ \si -> var $ f si
eps a = Session $ const $ eps a
instance IxMonadReader (Maybe SessionInfo) Session where
ask = Session $ \si -> return si
local f m = Session $ \si -> runSessionC m (f si)
reader f = Session $ \si -> return (f si)
instance IxMonadIO Session where
liftIO = liftP . P.liftIO
-- | Lifts a `Process` computation
liftP :: Process a -> Session s s a
liftP p = Session $ \_ -> rep $ lift p
-- | Lifts a `STTerm` computation
liftST :: STTerm Process s r a -> Session s r a
liftST st = Session $ \_ -> rep st