Skip to content

A generalization of distributed-process functions to a MonadProcess typeclass and standard transformer instances using monad-control and similar technique.

License

Notifications You must be signed in to change notification settings

jeremyjh/distributed-process-lifted

Repository files navigation

Overview

This Haskell library is intended to ease usage of monad transformer stacks with the Cloud Haskell distributed-process library. This package provides typeclasses and functions for lifting functions and control operations (such as spawnLocal) from the Process monad into transformer stacks based on the Process monad, in very similar way that the lifted-base package lifts IO functions into more generalized functions constrained to MonadIO and MonadBaseControl IO.

This library uses MonadTransControl and a new typeclass - Control.Distributed.Process.Lifted.Class.MonadProcessBase - which plays the same role as MonadBaseControl IO. Instances are provided for all the transformers types - so stacks based on any of these (e.g. ReaderT Config Process a) can be used out-of-the-box.

The Control.Distributed.Process.Lifted module exports all the same symbols as found in Control.Distributed.Process, but they are all generalized. Where appropriate it re-exports the more general functions from lifted-base (e.g. catch) rather than the versions re-implemented for Process.

The Control.Distributed.Process.Lifted.Extras module provides some useful utilities for working with Cloud Haskell on top of another IO-based monad.

Example

For a motivation at a glance, consider the following two programs which perform the same function using the same monad stack, the first using lifted functions and the second using the base functions.

import Network.Transport.TCP (createTransport, defaultTCPParameters)
import Control.Distributed.Process.Lifted
import Control.Distributed.Process.Node
import Control.Concurrent.Lifted (threadDelay)
import Control.Monad.Reader (ReaderT, runReaderT, ask)

type MyConfig = String
type MyApp a = ReaderT MyConfig Process a

runMyApp :: LocalNode -> MyConfig -> MyApp () -> IO ()
runMyApp node conf ma = runProcess node (runReaderT ma conf)

useSomeConfig :: MyApp ()
useSomeConfig = ask >>= say

main :: IO ()
main = do
    Right t <- createTransport "127.0.0.1" "10501" defaultTCPParameters
    node <- newLocalNode t initRemoteTable
    runMyApp node "some config data" $ do
       parent <- getSelfPid
       spawnLocal $ do
         useSomeConfig
         send parent "all done"
       "all done" <- expect
       return ()
    threadDelay (50*1000)

And using the Base Process:

import Network.Transport.TCP (createTransport, defaultTCPParameters)
import Control.Distributed.Process
import Control.Distributed.Process.Node
import Control.Concurrent.Lifted (threadDelay)
import Control.Monad.Reader (ReaderT, runReaderT, ask, lift)

type MyConfig = String
type MyApp a = ReaderT MyConfig Process a

runMyApp :: LocalNode -> MyConfig -> MyApp () -> IO ()
runMyApp node conf ma = runProcess node (runReaderT ma conf)

withMyApp :: MyConfig -> MyApp a -> Process a
withMyApp conf ma = runReaderT ma conf

useSomeConfig :: MyApp ()
useSomeConfig = do
  config <- ask
  lift $ say config

main :: IO ()
main = do
    Right t <- createTransport "127.0.0.1" "10501" defaultTCPParameters
    node <- newLocalNode t initRemoteTable
    runMyApp node "some config data" $ do
       parent <- lift getSelfPid
       config <- ask
       lift $ spawnLocal $ do
         withMyApp config $ do
            useSomeConfig
            lift $ send parent "all done"
       "all done" <- lift expect
       return ()
    threadDelay (50*1000)

About

A generalization of distributed-process functions to a MonadProcess typeclass and standard transformer instances using monad-control and similar technique.

Resources

License

Stars

Watchers

Forks

Packages

No packages published