Portability | Many GHC only extensions |
---|---|
Stability | experimental |
Maintainer | Matthew Mirman <mmirman@andrew.cmu.edu> |
Safe Haskell | None |
Declaration of the frontend for RPC.
- class Host a where
- getLocation :: a -> String
- getPort :: a -> Integer
- getValue :: a
- data WIO w m a
- class (Functor m, Monad m, MonadIO m, Forkable m) => Servable m
- liftIO :: MonadIO m => forall a. IO a -> m a
- runServer :: forall w m. (Servable m, Host w) => WIO w m () -> m ()
- runServerBG :: Host w => WIO w IO () -> IO ThreadId
- onHost :: forall w m. (Servable m, Host w) => w -> WIO w m ()
- autoService :: Name -> Q Exp
- makeHost :: String -> String -> Integer -> Q [Dec]
- makeServices :: [Name] -> Q Exp
- rpcCall :: Name -> Q Exp
- class Monad m => Forkable m where
- class MonadTrans t where
Documentation
declares that the world is a host. It should
only have one constructor, and the location and port should be invariant
of the given constructor.
Specifically, Host
WorldgetLocation
and getPort
should work even if bottom is supplied.
is a newtype over a server transformer that adds the phantom
host argument WIO
w m aw
(Sendable m a' a, Sendable m b b') => Sendable m (a -> b) (a' -> WIO w m b') | |
MonadTrans (WIO w) | |
Monad m => Monad (WIO w m) | |
Functor m => Functor (WIO w m) | |
MonadIO m => MonadIO (WIO w m) | |
Forkable m => Forkable (WIO w m) | |
Servable m => Servable (WIO w m) | |
(Host w, Servable m, Sendable m a a') => Service (WIO w m a) m w | |
(Sendable m' a a', Host w, Host w', Servable m, Servable m') => RPC (WIO w m a) (WIO w' m' a') m' w' |
class (Functor m, Monad m, MonadIO m, Forkable m) => Servable m Source
Servable
is a declaration that the given monad can be made into a
servlet.
runServer :: forall w m. (Servable m, Host w) => WIO w m () -> m ()Source
runServer
runs a name server and doesn't return
runServerBG :: Host w => WIO w IO () -> IO ThreadIdSource
runServerBG
runs a name server on a background thread and does return
onHost :: forall w m. (Servable m, Host w) => w -> WIO w m ()Source
onHost
declares that the code is running on the given host.
it is usefull when a type inference is wanted, but the action
also needs to be made into a service and used as a remote procedure
autoService :: Name -> Q ExpSource
$(
finds all services declared in the
module that definitely run on the given world,
and makes them listen for incoming requests.
autoService
'World)
makeHost :: String -> String -> Integer -> Q [Dec]Source
$(
makes a makeHost
"HostName" "hostLocation" hostPortNumber)newtype HostName
and declares an instance
.
Host
HostName
makeServices :: [Name] -> Q ExpSource
$(
makes all given
services listen for incoming requests.
makeServices
['service1 ,..., 'serviceN])
rpcCall :: Name -> Q ExpSource
$(
simply splices in
rpcCall
'serviceNm)
which is typed in a manner
similar to typeofcall.
realRemoteCall
(undefined :: typeofcall) "serviceNm"
Example: Making remote Calls
This example shows how to make remote procedure from a Client to a Host. It also shows how to send functions, even though these will space leak.
-- LANGUAGE TemplateHaskell, KindSignatures, FlexibleContexts module Main where import Network.Remote.RPC
First, hosts must be declared. In the future, hosts might be declared in a configuration file such that they can be configured at runtime rather than only at compile time.
$(makeHost
"Client" "localhost" 9000) $(makeHost
"Server" "localhost" 9001)
The following services will run on the server.
doubleServer :: Integer ->WIO
Server IO Integer doubleServer t = return $ t + t addServer :: Integer ->WIO
Server IO (Integer -> Integer) addServer t = return (t +)
When used, addServer
will return a function of type Integer ->
because the resulting function will actually be a remote call. Every time WIO
w IO IntegeraddServer
is called, it turns the function into a permanent service. This should change in the
future. For now, recognize that this can create a space leak if not used carefully.
client = do onHost Client double <- $(rpcCall 'doubleServer) 3 liftIO $ putStrLn $ "r(h3+h3) ? " ++ show double add <- $(rpcCall 'addServer) 4 r <- add 6 -- add :: Integer -> WIO Client IO Integer liftIO $ putStrLn $ "r(h4 +) h6 ? " ++ show r
Despite rpcCall
being a template splice, the resulting splice is type safe:
$(rpcCall
'doubleServer) :: (Host
w,Servable
m) => Integer ->WIO
w m Integer
Now we declare the runtime. Usually this would be in two different mains, but for educational and testing purposes, both the client and server can be run from the same main.
main = dorunServerBG
$(autoService 'Server)runServer
client
-
$(
looks for services declared in the file which definitely run on server, and runs them as services on the intended host (autoService
'Server)Server
in this case). -
runServerBG
runs a service server on a background OS thread, and returns -
runServer
runs a service server and does not return. - When run:
>>>
:main
r(h3+h3) ? 6 r(h4 +) h6 ? 10
Where rVal
means Val is on the server and hVal
means Val is on the client.
class MonadTrans t where
The class of monad transformers. Instances should satisfy the
following laws, which state that lift
is a transformer of monads:
MonadTrans ListT | |
MonadTrans MaybeT | |
MonadTrans IdentityT | |
MonadTrans AIO | |
MonadTrans (ContT r) | |
Error e => MonadTrans (ErrorT e) | |
MonadTrans (ReaderT r) | |
MonadTrans (StateT s) | |
MonadTrans (StateT s) | |
Monoid w => MonadTrans (WriterT w) | |
Monoid w => MonadTrans (WriterT w) | |
MonadTrans (WIO w) | |
Monoid w => MonadTrans (RWST r w s) | |
Monoid w => MonadTrans (RWST r w s) |