-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Cloud Haskell: Erlang-style concurrency in Haskell -- -- This is an implementation of Cloud Haskell, as described in Towards -- Haskell in the Cloud by Jeff Epstein, Andrew Black, and Simon -- Peyton Jones -- (http://research.microsoft.com/en-us/um/people/simonpj/papers/parallel/), -- although some of the details are different. The precise message -- passing semantics are based on A unified semantics for future -- Erlang by Hans Svensson, Lars-Åke Fredlund and Clara Benac Earle. -- You will probably also want to install a Cloud Haskell backend such as -- distributed-process-simplelocalnet. @package distributed-process @version 0.2.3.0 -- | Binary instances for TypeRep, and TypeRep -- equality (bug workaround) module Control.Distributed.Process.Internal.TypeRep -- | Compare two type representations -- -- For base >= 4.6 this compares fingerprints, but older versions of -- base have a bug in the fingerprint construction -- (http://hackage.haskell.org/trac/ghc/ticket/5962) compareTypeRep :: TypeRep -> TypeRep -> Bool instance Binary TyCon instance Binary TypeRep instance Binary Fingerprint -- | Reimplementation of Dynamic that supports dynBind -- -- We don't have access to the internal representation of Dynamic, -- otherwise we would not have to redefine it completely. Note that we -- use this only internally, so the incompatibility with our -- Dynamic from the standard Dynamic is not important. module Control.Distributed.Process.Internal.Dynamic data Dynamic Dynamic :: TypeRep -> Any -> Dynamic toDyn :: Typeable a => a -> Dynamic fromDyn :: Typeable a => Dynamic -> a -> a fromDynamic :: Typeable a => Dynamic -> Maybe a dynTypeRep :: Dynamic -> TypeRep dynApply :: Dynamic -> Dynamic -> Maybe Dynamic dynApp :: Dynamic -> Dynamic -> Dynamic dynBind :: TyCon -> (forall a b. m a -> (a -> m b) -> m b) -> Dynamic -> Dynamic -> Maybe Dynamic dynBind' :: TyCon -> (forall a b. m a -> (a -> m b) -> m b) -> Dynamic -> Dynamic -> Dynamic -- | Dynamically typed Kleisli composition dynKleisli :: TyCon -> (forall a b c. (a -> m b) -> (b -> m c) -> a -> m c) -> Dynamic -> Dynamic -> Maybe Dynamic -- | The function unsafeCoerce# allows you to side-step the -- typechecker entirely. That is, it allows you to coerce any type into -- any other type. If you use this function, you had better get it right, -- otherwise segmentation faults await. It is generally used when you -- want to write a program that you know is well-typed, but where -- Haskell's type system is not expressive enough to prove that it is -- well typed. -- -- The following uses of unsafeCoerce# are supposed to work -- (i.e. not lead to spurious compile-time or run-time crashes): -- --
-- instance Typeable a => Serializable (Static a) ---- -- The Typeable constraint (not present in the original Cloud -- Haskell paper) makes it possible to do a type check during -- deserialization. newtype Static a Static :: StaticLabel -> Static a -- | Apply two static values staticApply :: Static (a -> b) -> Static a -> Static b -- | Co-monadic duplicate for static values staticDuplicate :: Typeable a => Static a -> Static (Static a) staticTypeOf :: Typeable a => a -> Static a typeOfStaticLabel :: StaticLabel -> TypeRep -- | A closure is a static value and an encoded environment data Closure a Closure :: (Static (ByteString -> a)) -> ByteString -> Closure a -- | Runtime dictionary for unstatic lookups data RemoteTable RemoteTable :: Map String Dynamic -> RemoteTable _remoteTableLabels :: RemoteTable -> Map String Dynamic -- | Reification of Serializable (see -- Control.Distributed.Process.Closure) data SerializableDict a SerializableDict :: SerializableDict a -- | Messages consist of their typeRep fingerprint and their encoding data Message Message :: Fingerprint -> ByteString -> Message messageFingerprint :: Message -> Fingerprint messageEncoding :: Message -> ByteString -- | Turn any serialiable term into a message createMessage :: Serializable a => a -> Message -- | Serialize a message messageToPayload :: Message -> [ByteString] -- | Deserialize a message payloadToMessage :: [ByteString] -> Message -- | MonitorRef is opaque for regular Cloud Haskell processes data MonitorRef MonitorRef :: Identifier -> Int32 -> MonitorRef -- | ID of the entity to be monitored monitorRefIdent :: MonitorRef -> Identifier -- | Unique to distinguish multiple monitor requests by the same process monitorRefCounter :: MonitorRef -> Int32 -- | Message sent by process monitors data ProcessMonitorNotification ProcessMonitorNotification :: MonitorRef -> ProcessId -> DiedReason -> ProcessMonitorNotification -- | Message sent by node monitors data NodeMonitorNotification NodeMonitorNotification :: MonitorRef -> NodeId -> DiedReason -> NodeMonitorNotification -- | Message sent by channel (port) monitors data PortMonitorNotification PortMonitorNotification :: MonitorRef -> SendPortId -> DiedReason -> PortMonitorNotification -- | Exceptions thrown when a linked process dies data ProcessLinkException ProcessLinkException :: ProcessId -> DiedReason -> ProcessLinkException -- | Exception thrown when a linked node dies data NodeLinkException NodeLinkException :: NodeId -> DiedReason -> NodeLinkException -- | Exception thrown when a linked channel (port) dies data PortLinkException PortLinkException :: SendPortId -> DiedReason -> PortLinkException -- | Why did a process die? data DiedReason -- | Normal termination DiedNormal :: DiedReason -- | The process exited with an exception (provided as String -- because Exception does not implement Binary) DiedException :: String -> DiedReason -- | We got disconnected from the process node DiedDisconnect :: DiedReason -- | The process node died DiedNodeDown :: DiedReason -- | Invalid (processnodechannel) identifier DiedUnknownId :: DiedReason -- | (Asynchronous) reply from unmonitor newtype DidUnmonitor DidUnmonitor :: MonitorRef -> DidUnmonitor -- | (Asynchronous) reply from unlink newtype DidUnlinkProcess DidUnlinkProcess :: ProcessId -> DidUnlinkProcess -- | (Asynchronous) reply from unlinkNode newtype DidUnlinkNode DidUnlinkNode :: NodeId -> DidUnlinkNode -- | (Asynchronous) reply from unlinkPort newtype DidUnlinkPort DidUnlinkPort :: SendPortId -> DidUnlinkPort -- | SpawnRef are used to return pids of spawned processes newtype SpawnRef SpawnRef :: Int32 -> SpawnRef -- | (Asynchronius) reply from spawn data DidSpawn DidSpawn :: SpawnRef -> ProcessId -> DidSpawn -- | (Asynchronous) reply from whereis data WhereIsReply WhereIsReply :: String -> (Maybe ProcessId) -> WhereIsReply -- | Messages to the node controller data NCMsg NCMsg :: Identifier -> ProcessSignal -> NCMsg ctrlMsgSender :: NCMsg -> Identifier ctrlMsgSignal :: NCMsg -> ProcessSignal -- | Signals to the node controller (see NCMsg) data ProcessSignal Link :: Identifier -> ProcessSignal Unlink :: Identifier -> ProcessSignal Monitor :: MonitorRef -> ProcessSignal Unmonitor :: MonitorRef -> ProcessSignal Died :: Identifier -> DiedReason -> ProcessSignal Spawn :: (Closure (Process ())) -> SpawnRef -> ProcessSignal WhereIs :: String -> ProcessSignal Register :: String -> (Maybe ProcessId) -> ProcessSignal NamedSend :: String -> Message -> ProcessSignal localProcesses :: Accessor LocalNodeState (Map LocalProcessId LocalProcess) localPidCounter :: Accessor LocalNodeState Int32 localPidUnique :: Accessor LocalNodeState Int32 localConnections :: Accessor LocalNodeState (Map (Identifier, Identifier) Connection) localProcessWithId :: LocalProcessId -> Accessor LocalNodeState (Maybe LocalProcess) localConnectionBetween :: Identifier -> Identifier -> Accessor LocalNodeState (Maybe Connection) monitorCounter :: Accessor LocalProcessState Int32 spawnCounter :: Accessor LocalProcessState Int32 channelCounter :: Accessor LocalProcessState LocalSendPortId typedChannels :: Accessor LocalProcessState (Map LocalSendPortId TypedChannel) typedChannelWithId :: LocalSendPortId -> Accessor LocalProcessState (Maybe TypedChannel) remoteTableLabels :: Accessor RemoteTable (Map String Dynamic) remoteTableLabel :: String -> Accessor RemoteTable (Maybe Dynamic) instance Typeable LocalProcessId instance Typeable ProcessId instance Typeable1 SendPort instance Typeable1 ReceivePort instance Typeable StaticLabel instance Typeable1 Static instance Typeable1 Closure instance Typeable1 SerializableDict instance Typeable PortLinkException instance Typeable NodeLinkException instance Typeable ProcessLinkException instance Typeable PortMonitorNotification instance Typeable NodeMonitorNotification instance Typeable ProcessMonitorNotification instance Typeable DidUnmonitor instance Typeable DidUnlinkProcess instance Typeable DidUnlinkNode instance Typeable DidUnlinkPort instance Typeable SpawnRef instance Typeable DidSpawn instance Typeable WhereIsReply instance Typeable1 Process instance Eq NodeId instance Ord NodeId instance Binary NodeId instance Eq LocalProcessId instance Ord LocalProcessId instance Show LocalProcessId instance Eq ProcessId instance Ord ProcessId instance Eq SendPortId instance Ord SendPortId instance Eq Identifier instance Ord Identifier instance Binary (SendPort a) instance Show (SendPort a) instance Eq (SendPort a) instance Ord (SendPort a) instance Show StaticLabel instance Show (Static a) instance Show (Closure a) instance Eq MonitorRef instance Ord MonitorRef instance Show MonitorRef instance Show DiedReason instance Eq DiedReason instance Show PortLinkException instance Show NodeLinkException instance Show ProcessLinkException instance Show PortMonitorNotification instance Show NodeMonitorNotification instance Show ProcessMonitorNotification instance Binary DidUnmonitor instance Binary DidUnlinkProcess instance Binary DidUnlinkNode instance Binary DidUnlinkPort instance Show SpawnRef instance Binary SpawnRef instance Eq SpawnRef instance Show DidSpawn instance Show WhereIsReply instance Show ProcessSignal instance Functor Process instance Monad Process instance MonadIO Process instance MonadReader LocalProcess Process instance Applicative Process instance Show NCMsg instance Binary WhereIsReply instance Typeable a => Binary (Static a) instance Binary Identifier instance Binary SendPortId instance Binary DidSpawn instance Typeable a => Binary (Closure a) instance Binary DiedReason instance Binary ProcessSignal instance Binary MonitorRef instance Binary NCMsg instance Binary PortMonitorNotification instance Binary NodeMonitorNotification instance Binary ProcessMonitorNotification instance Binary ProcessId instance Binary LocalProcessId instance Exception PortLinkException instance Exception NodeLinkException instance Exception ProcessLinkException instance Show Message instance Show SendPortId instance Show Identifier instance Show ProcessId instance Show NodeId -- | Template Haskell support -- -- (In a separate file for convenience) module Control.Distributed.Process.Internal.Closure.TH -- | Create the closure, decoder, and metadata definitions for the given -- list of functions remotable :: [Name] -> Q [Dec] -- | Construct a static value. -- -- If f : forall a1 .. an. T then $(mkStatic 'f) :: forall -- a1 .. an. Static T. Be sure to pass f to -- remotable. mkStatic :: Name -> Q Exp -- | If f : T1 -> T2 is a monomorphic function then -- $(functionSDict 'f) :: Static (SerializableDict T1). -- -- Be sure to pass f to remotable. functionSDict :: Name -> Q Exp -- | If f : T1 -> Process T2 is a monomorphic function then -- $(functionTDict 'f) :: Static (SerializableDict T2). -- -- Be sure to pass f to remotable. functionTDict :: Name -> Q Exp -- | Combinators on static values module Control.Distributed.Process.Internal.Closure.Static -- | Static version of const staticConst :: (Typeable a, Typeable b) => Static (a -> b -> a) -- | Static version of flip staticFlip :: (Typeable a, Typeable b, Typeable c) => Static (a -> b -> c) -> Static (b -> a -> c) -- | Static version of fst staticFst :: (Typeable a, Typeable b) => Static ((a, b) -> a) -- | Static version of snd staticSnd :: (Typeable a, Typeable b) => Static ((a, b) -> b) -- | Static version of (.) staticCompose :: (Typeable a, Typeable b, Typeable c) => Static (b -> c) -> Static (a -> b) -> Static (a -> c) -- | Static version of first staticFirst :: (Typeable a, Typeable b, Typeable c) => Static ((a -> b) -> (a, c) -> (b, c)) -- | Static version of second staticSecond :: (Typeable a, Typeable b, Typeable c) => Static ((a -> b) -> (c, a) -> (c, b)) -- | Static version of (***) staticSplit :: (Typeable a, Typeable b, Typeable c, Typeable d) => Static (a -> c) -> Static (b -> d) -> Static ((a, b) -> (c, d)) -- | Static version of '()' staticUnit :: Static () -- | Static decoder, given a static serialization dictionary. -- -- See module documentation of Control.Distributed.Process.Closure -- for an example. staticDecode :: Typeable a => Static (SerializableDict a) -> Static (ByteString -> a) -- | Convert a static value into a closure. staticClosure :: Typeable a => Static a -> Closure a -- | Convert a serializable value into a closure. toClosure :: Serializable a => Static (SerializableDict a) -> a -> Closure a -- | Serialization dictionary for '()' sdictUnit :: Static (SerializableDict ()) -- | Serialization dictionary for ProcessId sdictProcessId :: Static (SerializableDict ProcessId) -- | Serialization dictionary for SendPort sdictSendPort :: Typeable a => Static (SerializableDict a) -> Static (SerializableDict (SendPort a)) __remoteTable :: RemoteTable -> RemoteTable module Control.Distributed.Process.Internal.Closure.MkClosure -- | Create a closure -- -- If f : T1 -> T2 is a monomorphic function then -- $(mkClosure 'f) :: T1 -> Closure T2. Be sure to pass -- f to remotable. mkClosure :: Name -> Q Exp module Control.Distributed.Process.Internal.Closure.Resolution resolveClosure :: RemoteTable -> Static a -> ByteString -> Maybe Dynamic module Control.Distributed.Process.Internal.Node sendPayload :: LocalNode -> Identifier -> Identifier -> [ByteString] -> IO () sendBinary :: Binary a => LocalNode -> Identifier -> Identifier -> a -> IO () sendMessage :: Serializable a => LocalNode -> Identifier -> Identifier -> a -> IO () -- | Cloud Haskell primitives -- -- We define these in a separate module so that we don't have to rely on -- the closure combinators module Control.Distributed.Process.Internal.Primitives -- | Send a message send :: Serializable a => ProcessId -> a -> Process () -- | Wait for a message of a specific type expect :: Serializable a => Process a -- | Create a new typed channel newChan :: Serializable a => Process (SendPort a, ReceivePort a) -- | Send a message on a typed channel sendChan :: Serializable a => SendPort a -> a -> Process () -- | Wait for a message on a typed channel receiveChan :: Serializable a => ReceivePort a -> Process a -- | Merge a list of typed channels. -- -- The result port is left-biased: if there are messages available on -- more than one port, the first available message is returned. mergePortsBiased :: Serializable a => [ReceivePort a] -> Process (ReceivePort a) -- | Like mergePortsBiased, but with a round-robin scheduler (rather -- than left-biased) mergePortsRR :: Serializable a => [ReceivePort a] -> Process (ReceivePort a) -- | Opaque type used in receiveWait and receiveTimeout data Match b -- | Test the matches in order against each message in the queue receiveWait :: [Match b] -> Process b -- | Like receiveWait but with a timeout. -- -- If the timeout is zero do a non-blocking check for matching messages. -- A non-zero timeout is applied only when waiting for incoming messages -- (that is, after we have checked the messages that are already -- in the mailbox). receiveTimeout :: Int -> [Match b] -> Process (Maybe b) -- | Match against any message of the right type match :: Serializable a => (a -> Process b) -> Match b -- | Match against any message of the right type that satisfies a predicate matchIf :: Serializable a => (a -> Bool) -> (a -> Process b) -> Match b -- | Remove any message from the queue matchUnknown :: Process b -> Match b -- | Terminate (throws a ProcessTerminationException) terminate :: Process a -- | Thrown by terminate data ProcessTerminationException ProcessTerminationException :: ProcessTerminationException -- | Our own process ID getSelfPid :: Process ProcessId -- | Get the node ID of our local node getSelfNode :: Process NodeId -- | Link to a remote process (asynchronous) -- -- Note that link provides unidirectional linking (see -- spawnSupervised). Linking makes no distinction between normal -- and abnormal termination of the remote process. link :: ProcessId -> Process () -- | Remove a link (synchronous) unlink :: ProcessId -> Process () -- | Monitor another process (asynchronous) monitor :: ProcessId -> Process MonitorRef -- | Remove a monitor (synchronous) unmonitor :: MonitorRef -> Process () -- | Log a string -- -- say message sends a message (time, pid of the current -- process, message) to the process registered as logger. By -- default, this process simply sends the string to stderr. -- Individual Cloud Haskell backends might replace this with a different -- logger process, however. say :: String -> Process () -- | Register a process with the local registry (asynchronous). -- -- The process to be registered does not have to be local itself. register :: String -> ProcessId -> Process () -- | Remove a process from the local registry (asynchronous). unregister :: String -> Process () -- | Query the local process registry (synchronous). whereis :: String -> Process (Maybe ProcessId) -- | Named send to a process in the local registry (asynchronous) nsend :: Serializable a => String -> a -> Process () -- | Register a process with a remote registry (asynchronous). -- -- The process to be registered does not have to live on the same remote -- node. registerRemote :: NodeId -> String -> ProcessId -> Process () -- | Remove a process from a remote registry (asynchronous). unregisterRemote :: NodeId -> String -> Process () -- | Query a remote process registry (synchronous) whereisRemote :: NodeId -> String -> Process (Maybe ProcessId) -- | Query a remote process registry (asynchronous) -- -- Reply will come in the form of a WhereIsReply message whereisRemoteAsync :: NodeId -> String -> Process () -- | Named send to a process in a remote registry (asynchronous) nsendRemote :: Serializable a => NodeId -> String -> a -> Process () -- | Deserialize a closure unClosure :: Typeable a => Closure a -> Process a -- | Lift catch catch :: Exception e => Process a -> (e -> Process a) -> Process a -- | Lift mask mask :: ((forall a. Process a -> Process a) -> Process b) -> Process b -- | Lift onException onException :: Process a -> Process b -> Process a -- | Lift bracket bracket :: Process a -> (a -> Process b) -> (a -> Process c) -> Process c -- | Lift bracket_ bracket_ :: Process a -> Process b -> Process c -> Process c -- | Lift finally finally :: Process a -> Process b -> Process a -- | Like expect but with a timeout expectTimeout :: Serializable a => Int -> Process (Maybe a) -- | Asynchronous version of spawn -- -- (spawn is defined in terms of spawnAsync and -- expect) spawnAsync :: NodeId -> Closure (Process ()) -> Process SpawnRef -- | Link to a node linkNode :: NodeId -> Process () -- | Link to a channel (send port) linkPort :: SendPort a -> Process () -- | Remove a node link (synchronous) unlinkNode :: NodeId -> Process () -- | Remove a channel (send port) link (synchronous) unlinkPort :: SendPort a -> Process () -- | Monitor a node monitorNode :: NodeId -> Process MonitorRef -- | Monitor a typed channel monitorPort :: Serializable a => SendPort a -> Process MonitorRef instance Typeable ProcessTerminationException instance Show ProcessTerminationException instance Exception ProcessTerminationException -- | Combinator for process closures module Control.Distributed.Process.Internal.Closure.CP -- | 'CP a b' represents the closure of a process parameterized by -- a and returning b. 'CP a b' forms a (restricted) -- generalized arrow (http://www.cs.berkeley.edu/~megacz/garrows/) type CP a b = Closure (a -> Process b) -- | CP introduction form cpIntro :: (Typeable a, Typeable b) => Closure (Process b) -> Closure (a -> Process b) -- | CP elimination form cpElim :: Typeable a => CP () a -> Closure (Process a) -- | Identity (Closure version of return) cpId :: Typeable a => CP a a -- | Left-to-right composition (Closure version of >=>) cpComp :: (Typeable a, Typeable b, Typeable c) => CP a b -> CP b c -> CP a c -- | First cpFirst :: (Typeable a, Typeable b, Typeable c) => CP a b -> CP (a, c) (b, c) -- | Second cpSecond :: (Typeable a, Typeable b, Typeable c) => CP a b -> CP (c, a) (c, b) -- | Split (Like ***) cpSplit :: (Typeable a, Typeable b, Typeable c, Typeable d) => CP a c -> CP b d -> CP (a, b) (c, d) -- | Left cancellation cpCancelL :: Typeable a => CP ((), a) a -- | Right cancellation cpCancelR :: Typeable a => CP (a, ()) a -- | Closure version of link cpLink :: ProcessId -> Closure (Process ()) -- | Closure version of unlink cpUnlink :: ProcessId -> Closure (Process ()) -- | Closure version of send cpSend :: Typeable a => Static (SerializableDict a) -> ProcessId -> Closure (a -> Process ()) -- | Closure version of expect cpExpect :: Typeable a => Static (SerializableDict a) -> Closure (Process a) -- | Closure version of newChan cpNewChan :: Typeable a => Static (SerializableDict a) -> Closure (Process (SendPort a, ReceivePort a)) -- | Not-quite-monadic return cpReturn :: Serializable a => Static (SerializableDict a) -> a -> Closure (Process a) -- | Not-quite-monadic bind (>>=) cpBind :: (Typeable a, Typeable b) => Closure (Process a) -> Closure (a -> Process b) -> Closure (Process b) -- | Monadic sequencing (>>) cpSeq :: Closure (Process ()) -> Closure (Process ()) -> Closure (Process ()) __remoteTable :: RemoteTable -> RemoteTable -- | Static values and Closures -- --
-- f :: forall a1 .. an. T -- f = ... ---- -- you can use a Template Haskell splice to create a static version of -- f: -- --
-- $(mkStatic 'f) :: forall a1 .. an. (Typeable a1, .., Typeable an) => Static T ---- -- Every module that you write that contains calls to mkStatic -- needs to have a call to remotable: -- --
-- remotable [ 'f, 'g, ... ] ---- -- where you must pass every function (or other value) that you pass as -- an argument to mkStatic. The call to remotable will -- create a definition -- --
-- __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 :: RemoteTable -- rtable = M1.__remoteTable -- . M2.__remoteTable -- . ... -- . Mn.__remoteTable -- $ initRemoteTable ---- -- NOTE: If you get a type error from ghc along these lines -- --
-- The exact Name `a_a30k' is not in scope -- Probable cause: you used a unique name (NameU) in Template Haskell but did not bind it ---- -- then you need to enable the ScopedTypeVariables language -- extension. -- --
-- decode :: Serializable a => ByteString -> a ---- -- Instead, you will need to reify the type class dictionary. Cloud -- Haskell comes with a reified version of Serializable: -- --
-- data SerializableDict a where -- SerializableDict :: Serializable a => SerializableDict a ---- -- Using the reified dictionary you can define -- --
-- decodeDict :: SerializableDict a -> ByteString -> a -- decodeDict SerializableDict = decode ---- -- where decodeDict is a normal (unqualified) polymorphic value -- and hence can be passed as an argument to remotable: -- --
-- $(mkStatic 'decodeDict) :: Typeable a => Static (SerializableDict a -> ByteString -> a) ---- --
-- staticApply :: Static (a -> b) -> Static a -> Static b ---- -- This is extremely useful. For example, Cloud Haskell comes with -- staticDecode defined as -- --
-- staticDecode :: Typeable a => Static (SerializableDict a) -> Static (ByteString -> a) -- staticDecode dict = $(mkStatic 'decodeDict) `staticApply` dict ---- -- staticDecode is used when defining closures (see below), and -- makes essential use of staticApply. -- -- Support for staticApply also makes it possible to define a rich -- set of combinators on static values, a number of which are -- provided in this module. -- --
-- sdictT :: SerializableDict T -- sdictT = SerializableDict ---- -- and then have -- --
-- $(mkStatic 'sdictT) :: Static (SerializableDict T) ---- -- However, since these dictionaries are so frequently required Cloud -- Haskell provides special support for them. When you call -- remotable on a monomorphic function f :: T1 -> -- T2 -- --
-- remotable ['f] ---- -- then a serialization dictionary is automatically created for you, -- which you can access with -- --
-- $(functionSDict 'f) :: Static (SerializableDict T1) ---- -- In addition, if f :: T1 -> Process T2, then a second -- dictionary is created -- --
-- $(functionTDict 'f) :: Static (SerializableDict T2) ---- --
-- isPrime :: Integer -> Process Bool ---- -- Then -- --
-- $(mkClosure 'isPrime) :: Integer -> Closure (Process Bool) ---- -- which you can then call, for example, to have a remote node -- check if a number is prime. -- -- In general, if you have a monomorphic function -- --
-- f :: T1 -> T2 ---- -- then -- --
-- $(mkClosure 'f) :: T1 -> Closure T2 ---- -- provided that T1 is serializable (*). -- --
-- data Closure a = Closure (Static (ByteString -> a)) ByteString ---- -- The splice $(mkClosure 'isPrime) above expands to (prettified -- a bit): -- --
-- let decoder :: Static (ByteString -> Process Bool) -- decoder = $(mkStatic 'isPrime) -- `staticCompose` -- staticDecode $(functionSDict 'isPrime) -- in Closure decoder (encode n) ---- -- where staticCompose is composition of static functions. Note -- that mkClosure makes use of the static serialization dictionary -- (functionSDict) created by remotable. -- --
-- {-# LANGUAGE TemplateHaskell #-}
-- import System.Environment (getArgs)
-- import Control.Distributed.Process
-- import Control.Distributed.Process.Closure
-- import Control.Distributed.Process.Backend.SimpleLocalnet
-- import Control.Distributed.Process.Node (initRemoteTable)
--
-- isPrime :: Integer -> Process Bool
-- isPrime n = return . (n `elem`) . takeWhile (<= n) . sieve $ [2..]
-- where
-- sieve :: [Integer] -> [Integer]
-- sieve (p : xs) = p : sieve [x | x <- xs, x `mod` p > 0]
--
-- remotable ['isPrime]
--
-- master :: [NodeId] -> Process ()
-- master [] = liftIO $ putStrLn "no slaves"
-- master (slave:_) = do
-- isPrime79 <- call $(functionTDict 'isPrime) slave ($(mkClosure 'isPrime) (79 :: Integer))
-- liftIO $ print isPrime79
--
-- main :: IO ()
-- main = do
-- args <- getArgs
-- case args of
-- ["master", host, port] -> do
-- backend <- initializeBackend host port rtable
-- startMaster backend master
-- ["slave", host, port] -> do
-- backend <- initializeBackend host port rtable
-- startSlave backend
-- where
-- rtable :: RemoteTable
-- rtable = __remoteTable initRemoteTable
--
--
-- -- instance Typeable a => Serializable (Static a) ---- -- The Typeable constraint (not present in the original Cloud -- Haskell paper) makes it possible to do a type check during -- deserialization. data Static a -- | Deserialize a closure unClosure :: Typeable a => Closure a -> Process a -- | Runtime dictionary for unstatic lookups data RemoteTable -- | Log a string -- -- say message sends a message (time, pid of the current -- process, message) to the process registered as logger. By -- default, this process simply sends the string to stderr. -- Individual Cloud Haskell backends might replace this with a different -- logger process, however. say :: String -> Process () -- | Register a process with the local registry (asynchronous). -- -- The process to be registered does not have to be local itself. register :: String -> ProcessId -> Process () -- | Remove a process from the local registry (asynchronous). unregister :: String -> Process () -- | Query the local process registry (synchronous). whereis :: String -> Process (Maybe ProcessId) -- | Named send to a process in the local registry (asynchronous) nsend :: Serializable a => String -> a -> Process () -- | Register a process with a remote registry (asynchronous). -- -- The process to be registered does not have to live on the same remote -- node. registerRemote :: NodeId -> String -> ProcessId -> Process () -- | Remove a process from a remote registry (asynchronous). unregisterRemote :: NodeId -> String -> Process () -- | Query a remote process registry (synchronous) whereisRemote :: NodeId -> String -> Process (Maybe ProcessId) -- | Query a remote process registry (asynchronous) -- -- Reply will come in the form of a WhereIsReply message whereisRemoteAsync :: NodeId -> String -> Process () -- | Named send to a process in a remote registry (asynchronous) nsendRemote :: Serializable a => NodeId -> String -> a -> Process () -- | (Asynchronous) reply from whereis data WhereIsReply WhereIsReply :: String -> (Maybe ProcessId) -> WhereIsReply -- | Lift catch catch :: Exception e => Process a -> (e -> Process a) -> Process a -- | Lift mask mask :: ((forall a. Process a -> Process a) -> Process b) -> Process b -- | Lift onException onException :: Process a -> Process b -> Process a -- | Lift bracket bracket :: Process a -> (a -> Process b) -> (a -> Process c) -> Process c -- | Lift bracket_ bracket_ :: Process a -> Process b -> Process c -> Process c -- | Lift finally finally :: Process a -> Process b -> Process a -- | Like expect but with a timeout expectTimeout :: Serializable a => Int -> Process (Maybe a) -- | Asynchronous version of spawn -- -- (spawn is defined in terms of spawnAsync and -- expect) spawnAsync :: NodeId -> Closure (Process ()) -> Process SpawnRef -- | Spawn a child process, have the child link to the parent and the -- parent monitor the child spawnSupervised :: NodeId -> Closure (Process ()) -> Process (ProcessId, MonitorRef) -- | Spawn a process and link to it -- -- Note that this is just the sequential composition of spawn and -- link. (The Unified semantics that underlies Cloud -- Haskell does not even support a synchronous link operation) spawnLink :: NodeId -> Closure (Process ()) -> Process ProcessId -- | Like spawnLink, but monitor the spawned process spawnMonitor :: NodeId -> Closure (Process ()) -> Process (ProcessId, MonitorRef) -- | Spawn a new process, supplying it with a new ReceivePort and -- return the corresponding SendPort. spawnChannel :: Typeable a => Static (SerializableDict a) -> NodeId -> Closure (ReceivePort a -> Process ()) -> Process (SendPort a) -- | (Asynchronius) reply from spawn data DidSpawn DidSpawn :: SpawnRef -> ProcessId -> DidSpawn -- | Spawn a process on the local node spawnLocal :: Process () -> Process ProcessId -- | Create a new typed channel, spawn a process on the local node, passing -- it the receive port, and return the send port spawnChannelLocal :: Serializable a => (ReceivePort a -> Process ()) -> Process (SendPort a)