distributed-process-0.2.0: src/Control/Distributed/Process/Closure.hs
-- | Implementation of 'Closure' that works around the absence of 'static'.
--
-- [Built-in closures]
--
-- We offer a number of standard commonly useful closures.
--
-- [Closure combinators]
--
-- Closures combinators allow to create closures from other closures. For
-- example, 'spawnSupervised' is defined as follows:
--
-- > spawnSupervised :: NodeId
-- > -> Closure (Process ())
-- > -> Process (ProcessId, MonitorRef)
-- > spawnSupervised nid proc = do
-- > us <- getSelfPid
-- > them <- spawn nid (linkClosure us `cpSeq` proc)
-- > ref <- monitor them
-- > return (them, ref)
--
-- [User-defined closures]
--
-- Suppose we have a monomorphic function
--
-- > addInt :: Int -> Int -> Int
-- > addInt x y = x + y
--
-- Then the Template Haskell splice
--
-- > remotable ['addInt]
--
-- creates a function
--
-- > $(mkClosure 'addInt) :: Int -> Closure (Int -> Int)
--
-- which can be used to partially apply 'addInt' and turn it into a 'Closure',
-- which can be sent across the network. Closures can be deserialized with
--
-- > unClosure :: Typeable a => Closure a -> Process a
--
-- In general, given a monomorphic function @f :: a -> b@ the corresponding
-- function @$(mkClosure 'f)@ will have type @a -> Closure b@.
--
-- The call to 'remotable' will also generate a function
--
-- > __remoteTable :: RemoteTable -> RemoteTable
--
-- which can be used to construct the 'RemoteTable' used to initialize
-- Cloud Haskell. You should have (at most) one call to 'remotable' per module,
-- and compose all created functions when initializing Cloud Haskell:
--
-- > let rtable = M1.__remoteTable
-- > . M2.__remoteTable
-- > . ...
-- > . Mn.__remoteTable
-- > $ initRemoteTable
--
-- See Section 6, /Faking It/, of /Towards Haskell in the Cloud/ for more info.
--
-- [Serializable Dictionaries]
--
-- Some functions (such as 'sendClosure' or 'returnClosure') require an
-- explicit (reified) serializable dictionary. To create such a dictionary do
--
-- > serializableDictInt :: SerializableDict Int
-- > serializableDictInt = SerializableDict
--
-- and then pass @'serializableDictInt@ to 'remotable'. This will fail if the
-- type is not serializable.
module Control.Distributed.Process.Closure
( -- * User-defined closures
remotable
, mkClosure
, SerializableDict(..)
-- * Built-in closures
, linkClosure
, unlinkClosure
, sendClosure
, returnClosure
, expectClosure
-- * Generic closure combinators
, closureApply
, closureConst
, closureUnit
-- * Arrow combinators for processes
, CP
, cpIntro
, cpElim
, cpId
, cpComp
, cpFirst
, cpSwap
, cpSecond
, cpPair
, cpCopy
, cpFanOut
, cpLeft
, cpMirror
, cpRight
, cpEither
, cpUntag
, cpFanIn
, cpApply
-- * Derived combinators for processes
, cpBind
, cpSeq
) where
import Control.Distributed.Process.Internal.Types (SerializableDict(..))
import Control.Distributed.Process.Internal.Closure.TH (remotable, mkClosure)
import Control.Distributed.Process.Internal.Closure.BuiltIn
( linkClosure
, unlinkClosure
, sendClosure
, returnClosure
, expectClosure
)
import Control.Distributed.Process.Internal.Closure.Combinators
( -- Generic combinators
closureApply
, closureConst
, closureUnit
-- Arrow combinators for processes
, CP
, cpIntro
, cpElim
, cpId
, cpComp
, cpFirst
, cpSwap
, cpSecond
, cpPair
, cpCopy
, cpFanOut
, cpLeft
, cpMirror
, cpRight
, cpEither
, cpUntag
, cpFanIn
, cpApply
-- Derived process operators
, cpBind
, cpSeq
)