This is a framework for remote procedure calls in haskell.
-
Usage is incredibly simple!
-
Calling a remote procedure is type safe.
-
Modal logic inspired worlds, aka hosts:
- Services run from the World IO monad, written
Host w => WIO w
- This allows world specific actions: if one world will be compiled to JS and one to x86, we could have the following types
- Services run from the World IO monad, written
putStrLn :: IO_World w => WIO w a
installTextBox :: JS_World w => WIO w ()
- Arbitrily complex remote procedures:
- Rather than only being able to call a remote function of one argument, we can call with any number of arguments
foo :: (Sendable a1 ,..., Sendable aN, Sendable b, Host w) => a1 -> ... -> aN -> WIO w b
- It can send pure functions across the wire and now garbage collect them.
instance (Serializable a) => Sendable a a
instance (Sendable a' a, Sendable b b') => Sendable (a -> b) (a' -> IO b')
-
Only local code can execute
- unlike some modal logic aproaches to mobile languages, the only code that can be executed is the code you compiled, and not code passed from world to world
-
State can be serialized with references.
-
To install, run cabal install
-
Hosts are declared at the declaration level
$(makeHost "WorldName" "host_location" #portNumber)
- Installing a remote service:
makeServices
registers a list of service names which all have the same hostautoService
automatically figures out which services in the given file run on the specified host and registers them. A good usage pattern is to provide all modules with services with a registration hook that can be appended to the main server.
main = runServer $(makeServices [ 'nameOfService1, ... , 'nameOfServiceN])
main = runServer $(autoService 'HostName)
module First where
services = $(autoService 'HostName)
module Second where
services = $(autoService 'HostName)
module Main where
import qualified First as F
import qualified Second as S
main = runServer $ F.services >> S.services
- Calling a remote service:
addServer :: Integer -> WIO Server (Integer -> Integer)
addServer t = do
Server <- world
return (t +)
getRemoteAdd = $(rpcCall 'addServer)
...
ghci> :t getRemoteAdd
getRemoteAdd :: Host w => Integer -> WIO w (Integer -> Integer)
- src/RPCTest.hs is an example.
- It runs two worlds, Client and Server, both on localhost, one on port 9000 and the other on 9001.
- To run and build it:
make run
- To build it:
make test
- To run it after building it:
./rpc-test