The Remote Monad Design Pattern
The remote monad design pattern is a way of making Remote Procedure Calls (RPCs), and other calls that leave the Haskell eco-system, considerably less expensive. The idea is that, rather than directly call a remote procedure, we instead give the remote procedure call a service-specific monadic type, and invoke the remote procedure call using a monadic “send” function. Specifically, A remote monad is a monad that has its evaluation function in a remote location, outside the local runtime system.
Example of a Remote Monad
By factoring the RPC into sending invocation and service name,
we can group together procedure calls, and amortize the cost
of the remote call. To give an example, Blank Canvas,
our library for remotely accessing the JavaScript HTML5 Canvas, has
a send
function, lineWidth
and
strokeStyle
services, and our remote monad is called
Canvas
:
If we wanted to change the (remote) line width,
the lineWidth
RPC can be invoked by combining send
and lineWidth
:
Likewise, if we wanted to change the (remote) stroke color,
the strokeStyle
RPC can be invoked by combining send
and strokeStyle
:
The key idea is that remote monadic commands can be locally combined before sending them to a remote server. For example:
The complication is that, in general, monadic commands can return a result, which may be used by subsequent commands. For example, if we add a monadic command that returns a Boolean,
we could use the result as follows:
The invocation of send
can also return a value:
Thus, while the monadic commands inside send
are executed in a remote location,
the results of those executions need to be made available for use locally.
This is the remote monad design pattern.
Uses of the Remote Monad Design Pattern
Once the Remote Monad design pattern is understood, many instances of
its use, or of related patterns, can be observed in the wild.
Here we highlight some examples, and give the type of the send
analog.
The tell-tale sign of a remote monad is the natural transformation
between a monad that offers specific services to the IO monad,
but there are other cases as well.
Package | Remote Monad | send |
---|---|---|
ncurses | Curses |
runCurses :: Curses a -> IO a |
HAXL | GenHaxl u |
runHaxl :: ... -> GenHaxl u a -> IO a |
mongoDB | Action m |
access :: ... -> Action m a -> m a |
Haste | Remote (...) |
onServer :: ... -> Remote (Server a) -> Client a |
Sunroof | JS t |
rsyncJS :: JS t a -> IO a |
hArduino | Arduino |
withArduino :: ... -> Arduino () -> IO () |
bus-pirate | BusPirateM |
runBusPirate :: ... -> BusPirateM a -> IO (Either String a) |
λ-bridge | BusCmd |
send :: ... -> BusCmd a -> IO (Maybe a) |
threepenny-gui | UI |
runUI :: ... -> UI a -> IO a |
accelerate | Arr |
runIn :: ... -> Acc a -> a |
sbv | Symbolic |
runSymbolic' :: ... -> Symbolic a -> IO (a, Result) |
mcpi | MCPI |
runMCPI :: MCPI a -> IO a |
remote-json | RPC |
send :: ... -> RPC a -> IO a |
plist-buddy | PlistBuddy |
send :: ... -> PlistBuddy a -> IO a |
We have also written some blog articles about some of these libraries, and how it uses the remote monad.
Related Work
- Semi-implicit batched remote code execution as staging
- There is no fork: an abstraction for efficient, concurrent, and concise data access
Publications
A. Gill, N. Sculthorpe, J. Dawson, A. Eskilson, A. Farmer, M. Grebe, J. Rosenbluth, R. Scott, and J. Stanton, “The remote monad design pattern,” in Proceedings of the 8th ACM SIGPLAN Symposium on Haskell, (New York, NY, USA), pp. 59–70, ACM, 2015.
M. Grebe and A. Gill, “Haskino: A remote monad for programming the Arduino,” in Practical Aspects of Declarative Languages, Lecture Notes in Computer Science, 2016.