-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Cloud Haskell -- -- Fault-tolerant distributed computing framework @package remote @version 0.1 -- | This module provides the Serializable type class and functions -- to convert to and from Payloads. It's implemented in terms of -- Haskell's Data.Binary. The message sending and receiving -- functionality in Remote.Process depends on this. module Remote.Encoding -- | Data that can be sent as a message must implement this class. The -- class has no functions of its own, but instead simply requires that -- the type implement both Typeable and Binary. Typeable -- can usually be derived automatically. Binary requires the put and get -- functions, which can be easily implemented by hand, or you can use the -- genericGet and genericPut flavors, which will work -- automatically for types implementing Data. class (Binary a, Typeable a) => Serializable a serialEncode :: Serializable a => a -> IO Payload serialEncodePure :: Serializable a => a -> Payload serialDecode :: Serializable a => Payload -> IO (Maybe a) serialDecodePure :: Serializable a => Payload -> Maybe a dynamicDecodePure :: Serializable a => DynamicPayload -> Maybe a dynamicEncodePure :: Serializable a => a -> DynamicPayload data Payload data DynamicPayload type PayloadLength = Int64 hPutPayload :: Handle -> Payload -> IO () hGetPayload :: Handle -> IO Payload payloadLength :: Payload -> PayloadLength getPayloadType :: Payload -> String getDynamicPayloadType :: DynamicPayload -> String getPayloadContent :: Payload -> ByteString -- | Data types that can be used in messaging must be serializable, which -- means that they must implement the get and put methods -- from Binary. If you are too lazy to write these functions -- yourself, you can delegate responsibility to this function. It's -- usually sufficient to do something like this: -- --
--   import Data.Data (Data)
--   import Data.Typeable (Typeable)
--   import Data.Binary (Binary, get, put)
--   data MyType = MkMyType Foobar Int [(String, Waddle Baz)]
--               | MkSpatula
--                    deriving (Data, Typeable)
--   instance Binary MyType where
--      put = genericPut
--      get = genericGet
--   
genericPut :: Data a => a -> Put -- | This is the counterpart genericPut genericGet :: Data a => Get a instance Typeable Payload instance Binary Payload instance (Binary a, Typeable a) => Serializable a -- | A simple type to represent a closure, that is, a function and its -- environment. The current implementation represents functions as -- strings, but this could be theoretically swapped out for the "static" -- mechanism described in the paper. module Remote.Closure -- | A data type representing a closure, that is, a function with its -- environment. In spirit, this is actually: -- --
--   data Closure a where
--     Closure :: Serializable v => Static (v -> a) -> v -> Closure a     
--   
-- -- where the Static type wraps a function with no non-static free -- variables. We simulate this behavior by identifying top-level -- functions as strings. See the paper for clarification. data Closure a Closure :: String -> Payload -> Closure a instance Typeable1 Closure instance Binary (Closure a) instance Show (Closure a) -- | Runtime metadata functions, part of the RPC mechanism module Remote.Reg -- | Creates a metadata lookup table based on compile-time metadata. You -- probably don't want to call this function yourself, but instead use -- Remote.Init.remoteInit. registerCalls :: [RemoteCallMetaData] -> Lookup data Lookup type Identifier = String putReg :: Typeable a => a -> Identifier -> Lookup -> Lookup getEntryByIdent :: Typeable a => Lookup -> Identifier -> Maybe a empty :: Lookup -- | Data of this type is generated at compile-time by remotable -- and can be used with registerCalls and remoteInit to -- create a metadata lookup table, Lookup. The name -- __remoteCallMetaData will be present in any module that uses -- remotable. type RemoteCallMetaData = Lookup -> Lookup -- | This module is the core of Cloud Haskell. It provides processes, -- messages, monitoring, and configuration. module Remote.Process -- | The monad ProcessM is the core of the process layer. Functions in the -- ProcessM monad may participate in messaging and create additional -- concurrent processes. You can create a ProcessM context from an -- IO context with the remoteInit function. data ProcessM a -- | Identifies a node somewhere on the network. These can be queried from -- getPeers. See also getSelfNode data NodeId -- | Identifies a process somewhere on the network. These are produced by -- the spawn family of functions and consumed by send. When -- a process ends, its process ID ceases to be valid. See also -- getSelfPid data ProcessId -- | Created by Remote.Peer.getPeers, this maps each role to a -- list of nodes that have that role. It can be examined directly or -- queried with findPeerByRole. type PeerInfo = Map String [NodeId] nullPid :: ProcessId -- | Returns the process ID of the current process. getSelfPid :: ProcessM ProcessId -- | Returns the node ID of the node that the current process is running -- on. getSelfNode :: ProcessM NodeId -- | Returns true if the given process ID is associated with the current -- node. Does not examine if the process is currently running. isPidLocal :: ProcessId -> ProcessM Bool -- | A simple way to receive messages. This will return the first message -- received of the specified type; if no such message is available, the -- function will block. Unlike the receive family of functions, -- this function does not allow the notion of choice in message -- extraction. expect :: Serializable a => ProcessM a -- | This monad provides the state and structure for matching received -- messages from the incoming message queue. It's the interface between -- the receive family of functions, and the match family, -- which together can express which messages can be accepted. data MatchM q a -- | Examines the message queue of the current process, matching each -- message against each of the provided message pattern clauses -- (typically provided by a function from the match family). If a -- message matches, the corresponding handler is invoked and its result -- is returned. If no message matches, Nothing is returned. receive :: [MatchM q ()] -> ProcessM (Maybe q) -- | Examines the message queue of the current process, matching each -- message against each of the provided message pattern clauses -- (typically provided by a function from the match family). If a -- message matches, the corresponding handler is invoked and its result -- is returned. If no message matches, the function blocks until a -- matching message is received. receiveWait :: [MatchM q ()] -> ProcessM q -- | Examines the message queue of the current process, matching each -- message against each of the provided message pattern clauses -- (typically provided by a function from the match family). If a -- message matches, the corresponding handler is invoked and its result -- is returned. If no message matches, the function blocks until a -- matching message is received, or until the specified time in -- microseconds has elapsed, at which point it will return Nothing. If -- the specified time is 0, this function is equivalent to -- receive. receiveTimeout :: Int -> [MatchM q ()] -> ProcessM (Maybe q) -- | Used to specify a message pattern in receiveWait and related -- functions. Only messages containing data of type a, where -- a is the argument to the user-provided function in the first -- parameter of match, will be removed from the queue, at which -- point the user-provided function will be invoked. match :: Serializable a => (a -> ProcessM q) -> MatchM q () -- | Similar to match, but allows for additional criteria to be -- checked prior to message acceptance. Here, the first user-provided -- function operates as a filter, and the message will be accepted only -- if it returns True. Once it's been accepted, the second user-defined -- function is invoked, as in match matchIf :: Serializable a => (a -> Bool) -> (a -> ProcessM q) -> MatchM q () matchCond :: Serializable a => (a -> Maybe (ProcessM q)) -> MatchM q () -- | A catch-all variant of match that invokes user-provided code -- and will extact any message from the queue. This is useful for -- matching against messages that are not recognized. Since message -- matching patterns are evaluated in order, this function, if used, -- should be the last element in the list of matchers given to -- receiveWait and similar functions. matchUnknown :: ProcessM q -> MatchM q () -- | A variant of matchUnknown that throws a -- UnknownMessageException if the process receives a message that -- isn't extracted by another message matcher. Equivalent to: -- --
--   matchUnknown (throw (UnknownMessageException "..."))
--   
matchUnknownThrow :: MatchM q () -- | A specialized version of match (for use with receive, -- receiveWait and friends) for catching process down messages. -- This way processes can avoid waiting forever for a response from -- another process that has crashed. Intended to be used within a -- withMonitor block, e.g.: -- --
--   withMonitor apid $
--     do send apid QueryMsg
--        receiveWait 
--        [
--          match (\AnswerMsg -> return "ok"),
--          matchProcessDown apid (return "aborted")   
--        ]
--   
matchProcessDown :: ProcessId -> ProcessM q -> MatchM q () -- | Sends a message to the given process. If the process isn't running or -- can't be accessed, this function will throw a -- TransmitException. The message must implement the -- Serializable interface. send :: Serializable a => ProcessId -> a -> ProcessM () -- | Like send, but in case of error returns a value rather than -- throw an exception. sendQuiet :: Serializable a => ProcessId -> a -> ProcessM TransmitStatus -- | Generates a log entry, using the process's current logging -- configuration. -- -- -- -- Both of the first two parameters may be used to filter log output. logS :: LogSphere -> LogLevel -> String -> ProcessM () -- | Uses the logging facility to produce non-filterable, programmatic -- output. Shouldn't be used for informational logging, but rather for -- application-level output. say :: String -> ProcessM () -- | Specifies the subsystem or region that is responsible for generating a -- given log entry. This is useful in conjunction with LogFilter -- to limit displayed log output to the particular area of your program -- that you are currently debugging. The SYS, TSK, and SAY spheres are -- used by the framework for messages relating to the Process layer, the -- Task layer, and the say function. The remainder of values are -- free for use at the application level. type LogSphere = String -- | Specifies the importance of a particular log entry. Can also be used -- to filter log output. data LogLevel -- | Non-suppressible application-level emission LoSay :: LogLevel LoFatal :: LogLevel LoCritical :: LogLevel LoImportant :: LogLevel -- | The default log level LoStandard :: LogLevel LoInformation :: LogLevel LoTrivial :: LogLevel -- | A preference as to what is done with log messages data LogTarget -- | Messages will be output to the console; the default LtStdout :: LogTarget -- | Log messages will be forwarded to the given node; please don't set up -- a loop LtForward :: NodeId -> LogTarget -- | Log messages will be appended to the given file LtFile :: FilePath -> LogTarget -- | Special value -- don't set this in your LogConfig! LtForwarded :: LogTarget -- | Specifies which log messages will be output. All log messages of -- importance below the current log level or not among the criterea given -- here will be suppressed. This type lets you limit displayed log -- messages to certain components. data LogFilter LfAll :: LogFilter LfOnly :: [LogSphere] -> LogFilter LfExclude :: [LogSphere] -> LogFilter -- | Expresses a current configuration of the logging subsystem, which -- determines which log messages to be output and where to send them when -- they are. Both processes and nodes have log configurations, set with -- setLogConfig and setNodeLogConfig respectively. The node -- log configuration is used for all processes that have not explicitly -- set their log configuration. Otherwise, the process log configuration -- takes priority. data LogConfig LogConfig :: LogLevel -> LogTarget -> LogFilter -> LogConfig -- | The lowest message priority that will be displayed logLevel :: LogConfig -> LogLevel -- | Where to send messages logTarget :: LogConfig -> LogTarget -- | Other filtering logFilter :: LogConfig -> LogFilter -- | Set the process's log configuration. This overrides any node-level log -- configuration setLogConfig :: LogConfig -> ProcessM () -- | Gets the currently active log configuration for the current process; -- if the current process doesn't have a log configuration set, the -- process's log configuration will be returned getLogConfig :: ProcessM LogConfig -- | Sets the node's log configuration setNodeLogConfig :: LogConfig -> ProcessM () -- | Sets the log configuration of a remote node. May throw -- TransmitException setRemoteNodeLogConfig :: NodeId -> LogConfig -> ProcessM () -- | The default log configuration represents a starting point for setting -- your own configuration. It is: -- --
--   logLevel = LoStandard
--   logTarget = LtStdout
--   logFilter = LfAll
--   
defaultLogConfig :: LogConfig -- | A ProcessM-flavoured variant of try ptry :: Exception e => ProcessM a -> ProcessM (Either e a) -- | A ProcessM-flavoured variant of timeout ptimeout :: Int -> ProcessM a -> ProcessM (Maybe a) -- | A ProcessM-flavoured variant of bracket pbracket :: (ProcessM a) -> (a -> ProcessM b) -> (a -> ProcessM c) -> ProcessM c -- | A ProcessM-flavoured variant of finally pfinally :: ProcessM a -> ProcessM b -> ProcessM a -- | Thrown by matchUnknownThrow in response to a message of a wrong -- type being received by a process data UnknownMessageException UnknownMessageException :: String -> UnknownMessageException -- | Thrown by Remote.Process system services in response to some -- problem data ServiceException ServiceException :: String -> ServiceException -- | Thrown by various network-related functions when communication with a -- host has failed data TransmitException TransmitException :: TransmitStatus -> TransmitException data TransmitStatus QteOK :: TransmitStatus QteUnknownPid :: TransmitStatus QteBadFormat :: TransmitStatus QteOther :: String -> TransmitStatus QtePleaseSendBody :: TransmitStatus QteBadNetworkMagic :: TransmitStatus QteNetworkError :: String -> TransmitStatus QteEncodingError :: String -> TransmitStatus QteDispositionFailed :: TransmitStatus QteLoggingError :: TransmitStatus QteConnectionTimeout :: TransmitStatus QteUnknownCommand :: TransmitStatus QteThrottle :: Int -> TransmitStatus -- | Assigns a name to the current process. The name is local to the node. -- On each node, each process may have only one name, and each name may -- be given to only one node. If this function is called more than once -- by the same process, or called more than once with the name on a -- single node, it will throw a ServiceException. The PID of a -- named process can be queried later with nameQuery. When the -- named process ends, its name will again become available. One reason -- to use named processes is to create node-local state. This example -- lets each node have its own favorite color, which can be changed and -- queried. -- --
--   nodeFavoriteColor :: ProcessM ()
--   nodeFavoriteColor =
--    do nameSet "favorite_color"
--       loop Blue
--    where loop color =
--        receiveWait
--           [ match (\newcolor -> return newcolor),
--             match (\pid -> send pid color >> return color)
--           ] >>= loop
--   
--   setFavoriteColor :: NodeId -> Color -> ProcessM ()
--   setFavoriteColor nid color =
--    do (Just pid) <- nameQuery nid "favorite_color"
--       send pid color
--   
--   getFavoriteColor :: NodeId -> ProcessM Color
--   getFavoriteColor nid =
--    do (Just pid) <- nameQuery nid "favorite_color"
--       mypid <- getSelfPid
--       send pid mypid
--       expect
--   
nameSet :: String -> ProcessM () -- | Query the PID of a named process on a particular node. If no process -- of that name exists, or if that process has ended, this function -- returns Nothing. nameQuery :: NodeId -> String -> ProcessM (Maybe ProcessId) -- | Similar to nameQuery but if the named process doesn't exist, it -- will be started from the given closure. If the process is already -- running, the closure will be ignored. nameQueryOrStart :: NodeId -> String -> Closure (ProcessM ()) -> ProcessM ProcessId -- | Create a new process on the current node. Returns the new process's -- identifier. Unlike spawn, this function does not need a -- Closure or a NodeId. spawnLocal :: ProcessM () -> ProcessM ProcessId -- | Start executing a process on the current node. This is a variation of -- spawnLocal which accepts two blocks of user-defined code. The -- first block is the main body of the code to run concurrently. The -- second block is a prefix which is run in the new process, prior -- to the main body, but its completion is guaranteed before spawnAnd -- returns. Thus, the prefix code is useful for initializing the new -- process synchronously. spawnLocalAnd :: ProcessM () -> ProcessM () -> ProcessM ProcessId -- | A synonym for spawnLocal forkProcess :: ProcessM () -> ProcessM ProcessId -- | Start a process running the code, given as a closure, on the specified -- node. If successful, returns the process ID of the new process. If -- unsuccessful, throw a TransmitException. spawn :: NodeId -> Closure (ProcessM ()) -> ProcessM ProcessId -- | A variant of spawn that allows greater control over how the -- remote process is started. spawnAnd :: NodeId -> Closure (ProcessM ()) -> AmSpawnOptions -> ProcessM ProcessId -- | A variant of spawn that starts the remote process with -- bidirectoinal monitoring, as in linkProcess spawnLink :: NodeId -> Closure (ProcessM ()) -> ProcessM ProcessId -- | If a remote process has been started in a paused state with -- spawnAnd , it will be running but inactive until unpaused. Use -- this function to unpause such a function. It has no effect on -- processes that are not paused or that have already been unpaused. unpause :: ProcessId -> ProcessM () data AmSpawnOptions AmSpawnOptions :: Bool -> Maybe ProcessId -> Maybe (ProcessId, MonitorAction) -> Maybe String -> AmSpawnOptions amsoPaused :: AmSpawnOptions -> Bool amsoLink :: AmSpawnOptions -> Maybe ProcessId amsoMonitor :: AmSpawnOptions -> Maybe (ProcessId, MonitorAction) amsoName :: AmSpawnOptions -> Maybe String defaultSpawnOptions :: AmSpawnOptions -- | The different kinds of monitoring available between processes. data MonitorAction -- | MaMonitor means that the monitor process will be sent a -- ProcessDownException message when the monitee terminates for any -- reason. MaMonitor :: MonitorAction -- | MaLink means that the monitor process will receive an asynchronous -- exception of type ProcessDownException when the monitee terminates for -- any reason MaLink :: MonitorAction -- | MaLinkError means that the monitor process will receive an -- asynchronous exception of type ProcessDownException when the monitee -- terminates abnormally MaLinkError :: MonitorAction -- | Part of the notification system of process monitoring, indicating why -- the monitor is being notified. data SignalReason -- | the monitee terminated normally SrNormal :: SignalReason -- | the monitee terminated with an uncaught exception, which is given as a -- string SrException :: String -> SignalReason -- | the monitee is believed to have ended or be inaccessible, as the node -- on which its running is not responding to pings. This may indicate a -- network bisection or that the remote node has crashed. SrNoPing :: SignalReason -- | SrInvalid: the monitee was not running at the time of the attempt to -- establish monitoring SrInvalid :: SignalReason -- | The main form of notification to a monitoring process that a monitored -- process has terminated. This data structure can be delivered to the -- monitor either as a message (if the monitor is of type -- MaMonitor) or as an asynchronous exception (if the monitor is -- of type MaLink or MaLinkError). It contains the PID of -- the monitored process and the reason for its nofication. data ProcessMonitorException ProcessMonitorException :: ProcessId -> SignalReason -> ProcessMonitorException -- | Establishes bidirectional abnormal termination monitoring between the -- current process and another. Monitoring established with linkProcess -- is bidirectional and signals only in the event of abnormal -- termination. In other words, linkProcess a is equivalent to: -- --
--   monitorProcess mypid a MaLinkError
--   monitorProcess a mypid MaLinkError
--   
linkProcess :: ProcessId -> ProcessM () -- | Establishes unidirectional processing of another process. The format -- is: -- --
--   monitorProcess monitor monitee action
--   
-- -- Here, -- -- -- -- Monitoring will remain in place until one of the processes ends or -- until unmonitorProcess is called. Calls to -- monitorProcess are cumulative, such that calling -- monitorProcess 3 three times on the same pair of processes will -- ensure that monitoring will stay in place until -- unmonitorProcess is called three times on the same pair of -- processes. If the monitee is not currently running, the monitor will -- be signalled immediately. See also MonitorAction. monitorProcess :: ProcessId -> ProcessId -> MonitorAction -> ProcessM () -- | Removes monitoring established by monitorProcess. Note that the -- type of monitoring, given in the third parameter, must match in order -- for monitoring to be removed. If monitoring has not already been -- established between these two processes, this function takes not -- action. unmonitorProcess :: ProcessId -> ProcessId -> MonitorAction -> ProcessM () -- | Establishes temporary monitoring of another process. The process to be -- monitored is given in the first parameter, and the code to run in the -- second. If the given process goes down while the code in the second -- parameter is running, a process down message will be sent to the -- current process, which can be handled by matchProcessDown. withMonitor :: ProcessId -> ProcessM a -> ProcessM a -- | Sends a small message to the specified node to determine if it's -- alive. If the node cannot be reached or does not respond within a time -- frame, the function will return False. pingNode :: NodeId -> ProcessM Bool -- | Invokes a function on a remote node. The function must be given by a -- closure. This function will block until the called function completes -- or the connection is broken. callRemote :: Serializable a => NodeId -> Closure (ProcessM a) -> ProcessM a callRemotePure :: Serializable a => NodeId -> Closure a -> ProcessM a callRemoteIO :: Serializable a => NodeId -> Closure (IO a) -> ProcessM a -- | Ends the current process in an orderly manner. terminate :: ProcessM a -- | Reads in configuration data from external sources, specifically from -- the command line arguments and a configuration file. The first -- parameter to this function determines whether command-line arguments -- are consulted. If the second parameter is not Nothing then it -- should be the name of the configuration file; an exception will be -- thrown if the specified file does not exist. Usually, this function -- shouldn't be called directly, but rather from -- Remote.Init.remoteInit, which also takes into account -- environment variables. Options set by command-line parameters have the -- highest precedence, followed by options read from a configuration -- file; if a configuration option is not explicitly specified anywhere, -- a reasonable default is used. The configuration file has a format, -- wherein one configuration option is specified on each line; the first -- token on each line is the name of the configuration option, followed -- by whitespace, followed by its value. Lines beginning with # are -- comments. Thus: -- --
--   # This is a sample configuration file
--   cfgHostName host3
--   cfgKnownHosts host1 host2 host3 host4
--   
-- -- Options may be specified on the command line similarly. Note that -- command-line arguments containing spaces must be quoted. -- --
--   ./MyProgram -cfgHostName=host3 -cfgKnownHosts='host1 host2 host3 host4'
--   
readConfig :: Bool -> Maybe FilePath -> IO Config emptyConfig :: Config -- | The Config structure encapsulates the user-settable configuration -- options for each node. This settings are usually read in from a -- configuration file or from the executable's command line; in either -- case, see Remote.Init.remoteInit and readConfig data Config Config :: !String -> !HostName -> !PortId -> !PortId -> !PortId -> !String -> ![String] -> !Int -> !Int -> !Int -> !String -> [String] -> Config -- | The user-assigned role of this node determines what its initial -- behavior is and how it presents itself to its peers. Default to NODE cfgRole :: Config -> !String -- | The hostname, used as a basis for creating the name of the node. If -- unspecified, the OS will be queried. Since the hostname is part of the -- nodename, the computer must be accessible to other nodes using this -- name. cfgHostName :: Config -> !HostName -- | The TCP port on which to listen to for new connections. If unassigned -- or 0, the OS will assign a free port. cfgListenPort :: Config -> !PortId -- | The TCP port on which to communicate with the local node registry, or -- to start the local node registry if it isn't already running. This -- defaults to 38813 and shouldn't be changed unless you have prohibitive -- firewall rules cfgLocalRegistryListenPort :: Config -> !PortId -- | The UDP port on which local peer discovery broadcasts are sent. -- Defaults to 38813, and only matters if you rely on dynamic peer -- discovery cfgPeerDiscoveryPort :: Config -> !PortId -- | The unique identifying string for this network or application. Must -- not contain spaces. The uniqueness of this string ensures that -- multiple applications running on the same physical network won't -- accidentally communicate with each other. All nodes of your -- application should have the same network magic. Defaults to MAGIC cfgNetworkMagic :: Config -> !String -- | A list of hosts where nodes may be running. When -- Remote.Peer.getPeers or Remote.Peer.getPeerStatic is -- called, each host on this list will be queried for its nodes. Only -- matters if you rely on static peer discovery. cfgKnownHosts :: Config -> ![String] -- | Microseconds to wait for a response from a system service on a remote -- node. If your network has high latency or congestion, you may need to -- increase this to avoid incorrect reports of node inaccessibility. 0 to -- wait indefinitely (not recommended). cfgRoundtripTimeout :: Config -> !Int -- | A limit on the number of simultaneous outgoing connections per node cfgMaxOutgoing :: Config -> !Int -- | Time in microseconds before an in-memory promise is flushed to disk. 0 -- to disable disk flush entirely. cfgPromiseFlushDelay :: Config -> !Int -- | Prepended to the filename of flushed promises. cfgPromisePrefix :: Config -> !String -- | Command-line arguments that are not part of the node configuration are -- placed here and can be examined by your application logConfig :: -- LogConfig cfgArgs :: Config -> [String] getConfig :: ProcessM (Config) -- | Returns command-line arguments provided to the executable, excluding -- any command line arguments that were processed by the framework. getCfgArgs :: ProcessM [String] -- | Creates a new Node object, given the specified configuration -- (usually created by readConfig) and function metadata table -- (usually create by Remote.Call.registerCalls). You probably -- want to use Remote.Init.remoteInit instead of this -- lower-level function. initNode :: Config -> Lookup -> IO (MVar Node) -- | Given a Node (created by initNode), start execution of -- user-provided code by invoking the given function with the node's -- cfgRole string. roleDispatch :: MVar Node -> (String -> ProcessM ()) -> IO () setDaemonic :: ProcessM () -- | Blocks until all non-daemonic processes of the given node have ended. -- Usually called on the main thread of a program. waitForThreads :: MVar Node -> IO () performFinalization :: MVar Node -> IO () -- | Starts a message-receive loop on the given node. You probably don't -- want to call this function yourself. forkAndListenAndDeliver :: MVar Node -> Config -> IO () runLocalProcess :: MVar Node -> ProcessM () -> IO ProcessId makeClosure :: (Typeable a, Serializable v) => String -> v -> ProcessM (Closure a) invokeClosure :: Typeable a => Closure a -> ProcessM (Maybe a) evaluateClosure :: Typeable b => Closure a -> ProcessM (Maybe (Payload -> b)) getQueueLength :: ProcessM Int nodeFromPid :: ProcessId -> NodeId localFromPid :: ProcessId -> LocalProcessId hostFromNid :: NodeId -> HostName type PortId = Int type LocalProcessId = Int -- | Contacts the local node registry and attempts to verify that it is -- alive. If the local node registry cannot be contacted, an exception -- will be thrown. localRegistryHello :: ProcessM () -- | Contacts the local node registry and attempts to register current -- node. You probably don't want to call this function yourself, as it's -- done for you in Remote.Init.remoteInit localRegistryRegisterNode :: ProcessM () localRegistryQueryNodes :: NodeId -> ProcessM (Maybe PeerInfo) -- | Contacts the local node registry and attempts to unregister current -- node. You probably don't want to call this function yourself, as it's -- done for you in Remote.Init.remoteInit localRegistryUnregisterNode :: ProcessM () sendSimple :: Serializable a => ProcessId -> a -> PayloadDisposition -> ProcessM TransmitStatus makeNodeFromHost :: String -> PortId -> NodeId getNewMessageLocal :: Node -> LocalProcessId -> STM (Maybe Message) getProcess :: ProcessM (Process) data Message data Process prNodeRef :: Process -> MVar Node roundtripResponse :: (Serializable a, Serializable b) => (a -> ProcessM (b, q)) -> MatchM q () roundtripResponseAsync :: (Serializable a, Serializable b) => (a -> (b -> ProcessM ()) -> ProcessM q) -> Bool -> MatchM q () roundtripQuery :: (Serializable a, Serializable b) => PayloadDisposition -> ProcessId -> a -> ProcessM (Either TransmitStatus b) roundtripQueryMulti :: (Serializable a, Serializable b) => PayloadDisposition -> [ProcessId] -> a -> ProcessM [Either TransmitStatus b] makePayloadClosure :: Closure a -> Maybe (Closure Payload) getLookup :: ProcessM (Lookup) diffTime :: UTCTime -> UTCTime -> Int roundtripQueryImpl :: (Serializable a, Serializable b) => Int -> PayloadDisposition -> ProcessId -> a -> (b -> c) -> [MatchM (Either TransmitStatus c) ()] -> ProcessM (Either TransmitStatus c) roundtripQueryUnsafe :: (Serializable a, Serializable b) => PayloadDisposition -> ProcessId -> a -> ProcessM (Either TransmitStatus b) data PayloadDisposition PldUser :: PayloadDisposition PldAdmin :: PayloadDisposition suppressTransmitException :: ProcessM a -> ProcessM (Maybe a) data Node getMessagePayload :: Serializable a => Message -> Maybe a getMessageType :: Message -> String startSpawnerService :: ProcessM () startLoggingService :: ProcessM () startProcessMonitorService :: ProcessM () startLocalRegistry :: Config -> Bool -> IO TransmitStatus startFinalizerService :: ProcessM () -> ProcessM () startNodeMonitorService :: ProcessM () startProcessRegistryService :: ProcessM () -- | Every host on which a node is running also needs a node registry, -- which arbitrates those nodes can responds to peer queries. If no -- registry is running, one will be automatically started when the -- framework is started, but the registry can be started independently, -- also. This function does that. standaloneLocalRegistry :: String -> IO () instance Typeable NodeId instance Typeable ProcessId instance Typeable PayloadDisposition instance Typeable ConfigException instance Typeable UnknownMessageException instance Typeable ServiceException instance Typeable ProcessTerminationException instance Typeable TransmitStatus instance Typeable TransmitException instance Typeable RoundtripHeader instance Typeable LogTarget instance Typeable LogFilter instance Typeable LogConfig instance Typeable LogMessage instance Typeable NodeMonitorCommand instance Typeable NodeMonitorSignal instance Typeable NodeMonitorInformation instance Typeable ProcessRegistryAnswer instance Typeable MonitorAction instance Typeable GlCommand instance Typeable GlSynchronous instance Typeable SignalReason instance Typeable GlSignal instance Typeable ProcessMonitorException instance Typeable AmCall instance Typeable AmSpawnOptions instance Typeable AmSpawnUnpause instance Typeable LocalProcessMessage instance Typeable1 ProcessM instance Typeable AmSpawn instance Typeable ProcessRegistryCommand instance Show Config instance Eq NodeId instance Ord NodeId instance Data NodeId instance Eq ProcessId instance Ord ProcessId instance Data ProcessId instance Read PayloadDisposition instance Show PayloadDisposition instance Eq PayloadDisposition instance Show ConfigException instance Show UnknownMessageException instance Show ServiceException instance Show ProcessTerminationException instance Show TransmitStatus instance Read TransmitStatus instance Show TransmitException instance Eq LogLevel instance Ord LogLevel instance Enum LogLevel instance Show LogLevel instance Ord ServiceId instance Eq ServiceId instance Enum ServiceId instance Show ServiceId instance Show MonitorAction instance Ord MonitorAction instance Eq MonitorAction instance Show SignalReason instance Show GlSignal instance Binary LocalProcessMessage instance Binary AmSpawnUnpause instance Binary AmSpawnOptions instance Binary AmCall instance Binary AmSpawn instance Show ProcessMonitorException instance Exception ProcessMonitorException instance Binary ProcessMonitorException instance Binary SignalReason instance Binary MonitorAction instance Binary GlCommand instance Binary GlSynchronous instance Binary GlSignal instance Binary ProcessRegistryAnswer instance Binary ProcessRegistryCommand instance Binary NodeMonitorInformation instance Binary NodeMonitorSignal instance Binary NodeMonitorCommand instance Show LogMessage instance Binary LogMessage instance Binary UTCTime instance Binary LogConfig instance Binary LogFilter instance Binary LogTarget instance Binary LogLevel instance Binary RoundtripHeader instance Binary TransmitStatus instance Exception ProcessTerminationException instance Exception ServiceException instance Exception UnknownMessageException instance Exception TransmitException instance Exception ConfigException instance Monad (MatchM q) instance MonadIO ProcessM instance Functor ProcessM instance Monad ProcessM instance Read ProcessId instance Show ProcessId instance Binary ProcessId instance Read NodeId instance Show NodeId instance Binary NodeId -- | Exposes mechanisms for a program built on the Remote.Process -- framework to discover nodes on the current network. Programs can -- perform node discovery manually, or they can use Remote.Task, -- which does it automatically. module Remote.Peer -- | Created by Remote.Peer.getPeers, this maps each role to a -- list of nodes that have that role. It can be examined directly or -- queried with findPeerByRole. type PeerInfo = Map String [NodeId] -- | Starts the discovery process, allowing this node to respond to queries -- from getPeersDynamic. You don't want to call this yourself, as it's -- called for you in Remote.Init.remoteInit startDiscoveryService :: ProcessM () -- | Returns information about all nodes on the current network that this -- node knows about. This function combines dynamic and static -- mechanisms. See documentation on getPeersStatic and -- getPeersDynamic for more info. This function depends on the -- configuration values cfgKnownHosts and -- cfgPeerDiscoveryPort. getPeers :: ProcessM PeerInfo -- | Returns a PeerInfo, containing a list of known nodes ordered by role. -- This information is acquired by querying the local node registry on -- each of the hosts in the cfgKnownHosts entry in this node's config. -- Hostnames that don't respond are assumed to be down and nodes running -- on them won't be included in the results. getPeersStatic :: ProcessM PeerInfo -- | Returns a PeerInfo, containing a list of known nodes ordered by role. -- This information is acquired by sending out a UDP broadcast on the -- local network; active nodes running the discovery service should -- respond with their information. If nodes are running outside of the -- local network, or if UDP broadcasts are disabled by firewall -- configuration, this won't return useful information; in that case, use -- getPeersStatic. This function takes a parameter indicating how long in -- microseconds to wait for hosts to respond. A number like 50000 is -- usually good enough, unless your network is highly congested or with -- high latency. getPeersDynamic :: Int -> ProcessM PeerInfo -- | Given a PeerInfo returned by getPeersDynamic or getPeersStatic, give a -- list of nodes registered as a particular role. If no nodes of that -- role are found, the empty list is returned. findPeerByRole :: PeerInfo -> String -> [NodeId] instance Typeable DiscoveryInfo instance Eq DiscoveryInfo instance Binary DiscoveryInfo -- | This module provides data dependency resolution and fault tolerance -- via promises (known elsewhere as futures). It's -- implemented in terms of the Remote.Process module. module Remote.Task data TaskM a -- | The basic data type for expressing data dependence in the TaskM -- monad. A Promise represents a value that may or may not have been -- computed yet; thus, it's like a distributed thunk (in the sense of a -- non-strict unit of evaluation). These are created by newPromise -- and friends, and the underlying value can be gotten with -- readPromise. data Promise a data PromiseList a PlChunk :: a -> (Promise (PromiseList a)) -> PromiseList a PlNil :: PromiseList a -- | Starts a new context for executing a TaskM environment. The -- node on which this function is run becomes a new master in a Task -- application; as a result, the application should only call this -- function once. The master will attempt to control all nodes that it -- can find; if you are going to be running more than one CH application -- on a single network, be sure to give each application a different -- network magic (via cfgNetworkMagic). The master TaskM environment -- created by this function can then spawn other threads, locally or -- remotely, using newPromise and friends. runTask :: TaskM a -> ProcessM a -- | Given a function (expressed here as a closure, see Remote.Call) -- that computes a value, returns a token identifying that value. This -- token, a Promise can be moved about even if the value hasn't -- been computed yet. The computing function will be started somewhere -- among the nodes visible to the current master, preferring those nodes -- that correspond to the defaultLocality. Afterwards, attempts to -- redeem the promise with readPromise will contact the node where -- the function is executing. newPromise :: Serializable a => Closure (TaskM a) -> TaskM (Promise a) -- | A variant of newPromise that lets the user specify a -- Locality. The other flavors of newPromise, such as -- newPromiseAtRole, newPromiseNear, and -- newPromiseHere at just shorthand for a call to this function. newPromiseAt :: Serializable a => Locality -> Closure (TaskM a) -> TaskM (Promise a) -- | A variant of newPromise that prefers to start the computing -- function on the same node where some other promise lives. The other -- promise is not evaluated. newPromiseNear :: (Serializable a, Serializable b) => Promise b -> Closure (TaskM a) -> TaskM (Promise a) -- | A variant of newPromise that prefers to start the computing -- function on the same node as the caller. Useful if you plan to use the -- resulting value locally. newPromiseHere :: Serializable a => Closure (TaskM a) -> TaskM (Promise a) -- | A variant of newPromise that prefers to start the computing -- functions on some set of nodes that have a given role (assigned by the -- cfgRole configuration option). newPromiseAtRole :: Serializable a => String -> Closure (TaskM a) -> TaskM (Promise a) -- | Like newPromise, but creates a promise whose values is already -- known. In other words, it puts a given, already-calculated value in a -- promise. Conceptually (but not syntactically, due to closures), you -- can consider it like this: -- --
--   toPromise a = newPromise (return a)
--   
toPromise :: Serializable a => a -> TaskM (Promise a) -- | A variant of toPromise that lets the user express a locality -- preference, i.e. some information about which node will become the -- owner of the new promise. These preferences will not necessarily be -- respected. toPromiseAt :: Serializable a => Locality -> a -> TaskM (Promise a) -- | Similar to toPromiseAt and newPromiseNear toPromiseNear :: (Serializable a, Serializable b) => Promise b -> a -> TaskM (Promise a) -- | Creates an immediate promise, which is to say, a promise in -- name only. Unlike a regular promise (created by toPromise), -- this kind of promise contains the value directly. The advantage is -- that promise redemption is very fast, requiring no network -- communication. The downside is that it the underlying data will be -- copied along with the promise. Useful only for small data. toPromiseImm :: Serializable a => a -> TaskM (Promise a) -- | Given a promise, gets the value that is being calculated. If the -- calculation has finished, the owning node will be contacted and the -- data moved to the current node. If the calculation has not finished, -- this function will block until it has. If the calculation failed by -- throwing an exception (e.g. divide by zero), then this function will -- throw an excption as well (a TaskException). If the node owning -- the promise is not accessible, the calculation will be restarted. readPromise :: Serializable a => Promise a -> TaskM a -- | A data structure that stores the important user-provided functions -- that are the namesakes of the MapReduce algorithm. The number of -- mapper processes can be controlled by the user by controlling the -- length of the string returned by mtChunkify. The number of reducer -- promises is controlled by the number of values values returned by -- shuffler. The user must provide their own mapper and reducer. For many -- cases, the default chunkifier (chunkify) and shuffler -- (shuffle) are adequate. data MapReduce rawinput input middle1 middle2 result MapReduce :: (input -> Closure (TaskM [middle1])) -> (middle2 -> Closure (TaskM result)) -> (rawinput -> [input]) -> ([middle1] -> [middle2]) -> MapReduce rawinput input middle1 middle2 result mtMapper :: MapReduce rawinput input middle1 middle2 result -> input -> Closure (TaskM [middle1]) mtReducer :: MapReduce rawinput input middle1 middle2 result -> middle2 -> Closure (TaskM result) mtChunkify :: MapReduce rawinput input middle1 middle2 result -> rawinput -> [input] mtShuffle :: MapReduce rawinput input middle1 middle2 result -> [middle1] -> [middle2] -- | The MapReduce algorithm, implemented in a very simple form on top of -- the Task layer. Its use depends on four user-determined data types: -- -- mapReduce :: (Serializable i, Serializable k, Serializable m, Serializable r) => MapReduce ri i k m r -> ri -> TaskM [r] -- | A convenient way to provide the mtChunkify function as part of -- mapReduce. chunkify :: Int -> [a] -> [[a]] -- | A convenient way to provide the mtShuffle function as part of -- mapReduce. shuffle :: Ord a => [(a, b)] -> [(a, [b])] -- | A Task-monadic version of say. Puts text messages in the log. tsay :: String -> TaskM () -- | Writes various kinds of messages to the Remote.Process log. tlogS :: LogSphere -> LogLevel -> String -> TaskM () -- | A specification of preference of where a promise should be allocated, -- among the nodes visible to the master. data Locality -- | The promise can be placed anywhere. LcUnrestricted :: Locality -- | The default preference is applied, which is for nodes having a role of -- NODE of WORKER LcDefault :: Locality -- | Nodes having the given roles will be preferred LcByRole :: [String] -> Locality -- | The given nodes will be preferred LcByNode :: [NodeId] -> Locality data TaskException TaskException :: String -> TaskException __remoteCallMetaData :: RemoteCallMetaData serialEncodeA :: Serializable a => a -> TaskM Payload serialDecodeA :: Serializable a => Payload -> TaskM (Maybe a) instance Typeable1 Promise instance Typeable1 PromiseList instance Typeable MmNewPromiseResponse instance Typeable MmStatus instance Typeable MmStatusResponse instance Typeable MmComplain instance Typeable MmComplainResponse instance Typeable TmNewPeer instance Typeable NmStartResponse instance Typeable NmRedeem instance Typeable NmRedeemResponse instance Typeable TaskException instance Typeable Queueing instance Typeable NmStart instance Typeable MmNewPromise instance Typeable1 TaskM instance Show TaskException instance Ord Queueing instance Eq Queueing instance Monad TaskM instance Binary Locality instance Binary Queueing instance Exception TaskException instance Binary NmRedeemResponse instance Binary NmRedeem instance Binary NmStartResponse instance Binary NmStart instance Binary TmNewPeer instance Binary MmComplainResponse instance Binary MmComplain instance Binary MmStatusResponse instance Binary MmStatus instance Binary MmNewPromiseResponse instance Binary MmNewPromise instance Serializable a => Binary (Promise a) instance Serializable a => Binary (PromiseList a) -- | Provides Template Haskell-based tools and syntactic sugar for dealing -- with closures module Remote.Call -- | A compile-time macro to provide easy invocation of closures. To use -- this, follow the following steps: -- --
    --
  1. First, enable Template Haskell in the module:
  2. --
-- --
--   {-# LANGUAGE TemplateHaskell #-}
--   module Main where
--   import Remote.Call (remotable)
--      ...
--   
-- --
    --
  1. Define your functions normally. Restrictions: function's type -- signature must be explicitly declared; no polymorphism; all parameters -- must implement Serializable; return value must be pure, or in one of -- the ProcessM, TaskM, or IO monads; probably other -- restrictions as well.
  2. --
-- --
--   greet :: String -> ProcessM ()
--   greet name = say ("Hello, "++name)
--   badFib :: Integer -> Integer
--   badFib 0 = 1
--   badFib 1 = 1
--   badFib n = badFib (n-1) + badFib (n-2)
--   
-- --
    --
  1. Use the remotable function to automagically generate stubs -- and closure generators for your functions:
  2. --
-- --
--   $( remotable ['greet, 'badFib] )
--   
-- -- remotable may be used only once per module. -- --
    --
  1. When you call remoteInit (usually the first thing in your -- program), be sure to give it the automagically generated function -- lookup tables from all modules that use remotable:
  2. --
-- --
--   main = remoteInit (Just "config") [Main.__remoteCallMetaData, OtherModule.__remoteCallMetaData] initialProcess
--   
-- --
    --
  1. Now you can invoke your functions remotely. When a function -- expects a closure, give it the name of the generated closure, rather -- than the name of the original function. If the function takes -- parameters, so will the closure. To start the greet function -- on someNode:
  2. --
-- --
--   spawn someNode (greet__closure "John Baptist")
--   
-- -- Note that we say greet__closure rather than just -- greet. If you prefer, you can use mkClosure instead, -- i.e. $(mkClosure 'greet), which will expand to -- greet__closure. To calculate a Fibonacci number remotely: -- --
--   val <- callRemotePure someNode (badFib__closure 5)
--   
remotable :: [Name] -> Q [Dec] -- | A compile-time macro to expand a function name to its corresponding -- closure name (if such a closure exists), suitable for use with -- spawn, callRemote, etc In general, using the syntax -- $(mkClosure foo) is the same as addressing the closure -- generator by name, that is, foo__closure. In some cases you -- may need to use mkClosureRec instead. mkClosure :: Name -> Q Exp -- | A variant of mkClosure suitable for expanding closures of -- functions declared in the same module, including that of the function -- it's used in. The Rec stands for recursive. If you get the -- Something is not in scope at a reify message when using -- mkClosure, try using this function instead. Using this function also -- turns off the static checks used by mkClosure, and therefore you are -- responsible for making sure that you use remotable with each -- function that may be an argument of mkClosureRec mkClosureRec :: Name -> Q Exp -- | Exposes a high-level interface for starting a node of a distributed -- program, taking into account a local configuration file, command line -- arguments, and commonly-used system processes. module Remote.Init -- | This is the usual way create a single node of distributed program. The -- intent is that remoteInit be called in your program's -- Main.main function. A typical call takes this form: -- --
--   main = remoteInit (Just "config") [Main.__remoteCallMetaData] initialProcess
--   
-- -- This will: -- --
    --
  1. Read the configuration file config in the current -- directory or, if specified, from the file whose path is given by the -- environment variable RH_CONFIG. If the given file does not -- exist or is invalid, an exception will be thrown.
  2. --
  3. Use the configuration given in the file as well as on the -- command-line to create a new node. The usual system processes will be -- started, including logging, discovery, and spawning.
  4. --
  5. Compile-time metadata, generated by -- Remote.Call.remotable, will used for invoking closures. -- Metadata from each module must be explicitly mentioned.
  6. --
  7. The function initialProcess will be called, given as a parameter a -- string indicating the value of the cfgRole setting of this node. -- initialProcess is provided by the user and provides an entrypoint for -- controlling node behavior on startup.
  8. --
remoteInit :: Maybe FilePath -> [RemoteCallMetaData] -> (String -> ProcessM ()) -> IO () -- | This module provides typed channels, an alternative approach to -- interprocess messaging. Typed channels can be used in combination with -- or instead of the the untyped channels available in the -- Remote.Process module via send. module Remote.Channel -- | A channel is a unidirectional communication pipeline with two ends: a -- sending port, and a receiving port. This is the sending port. A -- process holding this value can insert messages into the channel. -- SendPorts themselves can also be sent to other processes. The other -- side of the channel is the ReceivePort. data SendPort a -- | A process holding a ReceivePort can extract messages from the channel, -- which we inserted by the holder(s) of the corresponding -- SendPort. Critically, ReceivePorts, unlike SendPorts, are not -- serializable. This means that you can only receive messages through a -- channel on the node on which the channel was created. data ReceivePort a -- | Create a new channel, and returns both the SendPort and -- ReceivePort thereof. newChannel :: Serializable a => ProcessM (SendPort a, ReceivePort a) -- | Inserts a new value into the channel. sendChannel :: Serializable a => SendPort a -> a -> ProcessM () -- | Extract a value from the channel, in FIFO order. receiveChannel :: Serializable a => ReceivePort a -> ProcessM a data CombinedChannelAction b -- | Specifies a port and an adapter for combining ports via -- combinePortsBiased and combinePortsRR. combinedChannelAction :: Serializable a => ReceivePort a -> (a -> b) -> CombinedChannelAction b -- | This function lets us respond to messages on multiple channels by -- combining several ReceivePorts into one. The resulting port is -- the sum of the input ports, and will extract messages from all of them -- in FIFO order. The input ports are specified by -- combinedChannelAction, which also gives a converter function. -- After combining the underlying receive ports can still be used -- independently, as well. We provide two ways to combine ports, which -- differ bias they demonstrate in returning messages when more than one -- underlying channel is nonempty. combinePortsBiased will check ports in -- the order given by its argument, and so if the first channel always -- was a message waiting, it will. starve the other channels. The -- alternative is combinePortsRR. combinePortsBiased :: Serializable b => [CombinedChannelAction b] -> ProcessM (ReceivePort b) -- | See combinePortsBiased. This function differs from that one in -- that the order that the underlying ports are checked is rotated with -- each invocation, guaranteeing that, given enough invocations, every -- channel will have a chance to contribute a message. combinePortsRR :: Serializable b => [CombinedChannelAction b] -> ProcessM (ReceivePort b) -- | Similar to combinePortsBiased, with the difference that the the -- underlying ports must be of the same type, and you don't have the -- opportunity to provide an adapter function. mergePortsBiased :: Serializable a => [ReceivePort a] -> ProcessM (ReceivePort a) -- | Similar to combinePortsRR, with the difference that the the -- underlying ports must be of the same type, and you don't have the -- opportunity to provide an adapter function. mergePortsRR :: Serializable a => [ReceivePort a] -> ProcessM (ReceivePort a) -- | Terminate a channel. After calling this function, -- receiveChannel on that port (or on any combined port based on -- it) will either fail or block indefinitely, and sendChannel on -- the corresponding SendPort will fail. Any unread messages -- remaining in the channel will be lost. terminateChannel :: Serializable a => ReceivePort a -> ProcessM () instance Typeable1 SendPort instance Binary (SendPort a) -- | Cloud Haskell (previously Remote Haskell) is a distributed computing -- framework for Haskell. We can describe its interface as roughly two -- levels: the process layer, consisting of processes, messages, -- and fault monitoring; and the task layer, consisting of tasks, -- promises, and fault recovery. This summary module provides the most -- common interface functions for both layers, although advanced users -- might want to import names from the other constituent modules, as -- well. module Remote -- | This is the usual way create a single node of distributed program. The -- intent is that remoteInit be called in your program's -- Main.main function. A typical call takes this form: -- --
--   main = remoteInit (Just "config") [Main.__remoteCallMetaData] initialProcess
--   
-- -- This will: -- --
    --
  1. Read the configuration file config in the current -- directory or, if specified, from the file whose path is given by the -- environment variable RH_CONFIG. If the given file does not -- exist or is invalid, an exception will be thrown.
  2. --
  3. Use the configuration given in the file as well as on the -- command-line to create a new node. The usual system processes will be -- started, including logging, discovery, and spawning.
  4. --
  5. Compile-time metadata, generated by -- Remote.Call.remotable, will used for invoking closures. -- Metadata from each module must be explicitly mentioned.
  6. --
  7. The function initialProcess will be called, given as a parameter a -- string indicating the value of the cfgRole setting of this node. -- initialProcess is provided by the user and provides an entrypoint for -- controlling node behavior on startup.
  8. --
remoteInit :: Maybe FilePath -> [RemoteCallMetaData] -> (String -> ProcessM ()) -> IO () -- | The monad ProcessM is the core of the process layer. Functions in the -- ProcessM monad may participate in messaging and create additional -- concurrent processes. You can create a ProcessM context from an -- IO context with the remoteInit function. data ProcessM a -- | Identifies a node somewhere on the network. These can be queried from -- getPeers. See also getSelfNode data NodeId -- | Identifies a process somewhere on the network. These are produced by -- the spawn family of functions and consumed by send. When -- a process ends, its process ID ceases to be valid. See also -- getSelfPid data ProcessId -- | This monad provides the state and structure for matching received -- messages from the incoming message queue. It's the interface between -- the receive family of functions, and the match family, -- which together can express which messages can be accepted. data MatchM q a -- | Returns the process ID of the current process. getSelfPid :: ProcessM ProcessId -- | Returns the node ID of the node that the current process is running -- on. getSelfNode :: ProcessM NodeId -- | Sends a message to the given process. If the process isn't running or -- can't be accessed, this function will throw a -- TransmitException. The message must implement the -- Serializable interface. send :: Serializable a => ProcessId -> a -> ProcessM () -- | Like send, but in case of error returns a value rather than -- throw an exception. sendQuiet :: Serializable a => ProcessId -> a -> ProcessM TransmitStatus -- | Start a process running the code, given as a closure, on the specified -- node. If successful, returns the process ID of the new process. If -- unsuccessful, throw a TransmitException. spawn :: NodeId -> Closure (ProcessM ()) -> ProcessM ProcessId -- | Create a new process on the current node. Returns the new process's -- identifier. Unlike spawn, this function does not need a -- Closure or a NodeId. spawnLocal :: ProcessM () -> ProcessM ProcessId -- | A variant of spawn that allows greater control over how the -- remote process is started. spawnAnd :: NodeId -> Closure (ProcessM ()) -> AmSpawnOptions -> ProcessM ProcessId -- | A variant of spawn that starts the remote process with -- bidirectoinal monitoring, as in linkProcess spawnLink :: NodeId -> Closure (ProcessM ()) -> ProcessM ProcessId -- | Invokes a function on a remote node. The function must be given by a -- closure. This function will block until the called function completes -- or the connection is broken. callRemote :: Serializable a => NodeId -> Closure (ProcessM a) -> ProcessM a callRemotePure :: Serializable a => NodeId -> Closure a -> ProcessM a callRemoteIO :: Serializable a => NodeId -> Closure (IO a) -> ProcessM a data AmSpawnOptions AmSpawnOptions :: Bool -> Maybe ProcessId -> Maybe (ProcessId, MonitorAction) -> Maybe String -> AmSpawnOptions amsoPaused :: AmSpawnOptions -> Bool amsoLink :: AmSpawnOptions -> Maybe ProcessId amsoMonitor :: AmSpawnOptions -> Maybe (ProcessId, MonitorAction) amsoName :: AmSpawnOptions -> Maybe String defaultSpawnOptions :: AmSpawnOptions -- | Ends the current process in an orderly manner. terminate :: ProcessM a -- | A simple way to receive messages. This will return the first message -- received of the specified type; if no such message is available, the -- function will block. Unlike the receive family of functions, -- this function does not allow the notion of choice in message -- extraction. expect :: Serializable a => ProcessM a -- | Examines the message queue of the current process, matching each -- message against each of the provided message pattern clauses -- (typically provided by a function from the match family). If a -- message matches, the corresponding handler is invoked and its result -- is returned. If no message matches, Nothing is returned. receive :: [MatchM q ()] -> ProcessM (Maybe q) -- | Examines the message queue of the current process, matching each -- message against each of the provided message pattern clauses -- (typically provided by a function from the match family). If a -- message matches, the corresponding handler is invoked and its result -- is returned. If no message matches, the function blocks until a -- matching message is received. receiveWait :: [MatchM q ()] -> ProcessM q -- | Examines the message queue of the current process, matching each -- message against each of the provided message pattern clauses -- (typically provided by a function from the match family). If a -- message matches, the corresponding handler is invoked and its result -- is returned. If no message matches, the function blocks until a -- matching message is received, or until the specified time in -- microseconds has elapsed, at which point it will return Nothing. If -- the specified time is 0, this function is equivalent to -- receive. receiveTimeout :: Int -> [MatchM q ()] -> ProcessM (Maybe q) -- | Used to specify a message pattern in receiveWait and related -- functions. Only messages containing data of type a, where -- a is the argument to the user-provided function in the first -- parameter of match, will be removed from the queue, at which -- point the user-provided function will be invoked. match :: Serializable a => (a -> ProcessM q) -> MatchM q () -- | Similar to match, but allows for additional criteria to be -- checked prior to message acceptance. Here, the first user-provided -- function operates as a filter, and the message will be accepted only -- if it returns True. Once it's been accepted, the second user-defined -- function is invoked, as in match matchIf :: Serializable a => (a -> Bool) -> (a -> ProcessM q) -> MatchM q () -- | A catch-all variant of match that invokes user-provided code -- and will extact any message from the queue. This is useful for -- matching against messages that are not recognized. Since message -- matching patterns are evaluated in order, this function, if used, -- should be the last element in the list of matchers given to -- receiveWait and similar functions. matchUnknown :: ProcessM q -> MatchM q () -- | A variant of matchUnknown that throws a -- UnknownMessageException if the process receives a message that -- isn't extracted by another message matcher. Equivalent to: -- --
--   matchUnknown (throw (UnknownMessageException "..."))
--   
matchUnknownThrow :: MatchM q () -- | A specialized version of match (for use with receive, -- receiveWait and friends) for catching process down messages. -- This way processes can avoid waiting forever for a response from -- another process that has crashed. Intended to be used within a -- withMonitor block, e.g.: -- --
--   withMonitor apid $
--     do send apid QueryMsg
--        receiveWait 
--        [
--          match (\AnswerMsg -> return "ok"),
--          matchProcessDown apid (return "aborted")   
--        ]
--   
matchProcessDown :: ProcessId -> ProcessM q -> MatchM q () -- | Generates a log entry, using the process's current logging -- configuration. -- -- -- -- Both of the first two parameters may be used to filter log output. logS :: LogSphere -> LogLevel -> String -> ProcessM () -- | Uses the logging facility to produce non-filterable, programmatic -- output. Shouldn't be used for informational logging, but rather for -- application-level output. say :: String -> ProcessM () -- | Specifies the subsystem or region that is responsible for generating a -- given log entry. This is useful in conjunction with LogFilter -- to limit displayed log output to the particular area of your program -- that you are currently debugging. The SYS, TSK, and SAY spheres are -- used by the framework for messages relating to the Process layer, the -- Task layer, and the say function. The remainder of values are -- free for use at the application level. type LogSphere = String -- | A preference as to what is done with log messages data LogTarget -- | Messages will be output to the console; the default LtStdout :: LogTarget -- | Log messages will be forwarded to the given node; please don't set up -- a loop LtForward :: NodeId -> LogTarget -- | Log messages will be appended to the given file LtFile :: FilePath -> LogTarget -- | Special value -- don't set this in your LogConfig! LtForwarded :: LogTarget -- | Specifies which log messages will be output. All log messages of -- importance below the current log level or not among the criterea given -- here will be suppressed. This type lets you limit displayed log -- messages to certain components. data LogFilter LfAll :: LogFilter LfOnly :: [LogSphere] -> LogFilter LfExclude :: [LogSphere] -> LogFilter -- | Expresses a current configuration of the logging subsystem, which -- determines which log messages to be output and where to send them when -- they are. Both processes and nodes have log configurations, set with -- setLogConfig and setNodeLogConfig respectively. The node -- log configuration is used for all processes that have not explicitly -- set their log configuration. Otherwise, the process log configuration -- takes priority. data LogConfig LogConfig :: LogLevel -> LogTarget -> LogFilter -> LogConfig -- | The lowest message priority that will be displayed logLevel :: LogConfig -> LogLevel -- | Where to send messages logTarget :: LogConfig -> LogTarget -- | Other filtering logFilter :: LogConfig -> LogFilter -- | Specifies the importance of a particular log entry. Can also be used -- to filter log output. data LogLevel -- | Non-suppressible application-level emission LoSay :: LogLevel LoFatal :: LogLevel LoCritical :: LogLevel LoImportant :: LogLevel -- | The default log level LoStandard :: LogLevel LoInformation :: LogLevel LoTrivial :: LogLevel -- | Set the process's log configuration. This overrides any node-level log -- configuration setLogConfig :: LogConfig -> ProcessM () -- | Sets the node's log configuration setNodeLogConfig :: LogConfig -> ProcessM () -- | Gets the currently active log configuration for the current process; -- if the current process doesn't have a log configuration set, the -- process's log configuration will be returned getLogConfig :: ProcessM LogConfig -- | The default log configuration represents a starting point for setting -- your own configuration. It is: -- --
--   logLevel = LoStandard
--   logTarget = LtStdout
--   logFilter = LfAll
--   
defaultLogConfig :: LogConfig -- | Returns command-line arguments provided to the executable, excluding -- any command line arguments that were processed by the framework. getCfgArgs :: ProcessM [String] -- | Thrown by matchUnknownThrow in response to a message of a wrong -- type being received by a process data UnknownMessageException UnknownMessageException :: String -> UnknownMessageException -- | Thrown by Remote.Process system services in response to some -- problem data ServiceException ServiceException :: String -> ServiceException -- | Thrown by various network-related functions when communication with a -- host has failed data TransmitException TransmitException :: TransmitStatus -> TransmitException data TransmitStatus QteOK :: TransmitStatus QteUnknownPid :: TransmitStatus QteBadFormat :: TransmitStatus QteOther :: String -> TransmitStatus QtePleaseSendBody :: TransmitStatus QteBadNetworkMagic :: TransmitStatus QteNetworkError :: String -> TransmitStatus QteEncodingError :: String -> TransmitStatus QteDispositionFailed :: TransmitStatus QteLoggingError :: TransmitStatus QteConnectionTimeout :: TransmitStatus QteUnknownCommand :: TransmitStatus QteThrottle :: Int -> TransmitStatus -- | Assigns a name to the current process. The name is local to the node. -- On each node, each process may have only one name, and each name may -- be given to only one node. If this function is called more than once -- by the same process, or called more than once with the name on a -- single node, it will throw a ServiceException. The PID of a -- named process can be queried later with nameQuery. When the -- named process ends, its name will again become available. One reason -- to use named processes is to create node-local state. This example -- lets each node have its own favorite color, which can be changed and -- queried. -- --
--   nodeFavoriteColor :: ProcessM ()
--   nodeFavoriteColor =
--    do nameSet "favorite_color"
--       loop Blue
--    where loop color =
--        receiveWait
--           [ match (\newcolor -> return newcolor),
--             match (\pid -> send pid color >> return color)
--           ] >>= loop
--   
--   setFavoriteColor :: NodeId -> Color -> ProcessM ()
--   setFavoriteColor nid color =
--    do (Just pid) <- nameQuery nid "favorite_color"
--       send pid color
--   
--   getFavoriteColor :: NodeId -> ProcessM Color
--   getFavoriteColor nid =
--    do (Just pid) <- nameQuery nid "favorite_color"
--       mypid <- getSelfPid
--       send pid mypid
--       expect
--   
nameSet :: String -> ProcessM () -- | Query the PID of a named process on a particular node. If no process -- of that name exists, or if that process has ended, this function -- returns Nothing. nameQuery :: NodeId -> String -> ProcessM (Maybe ProcessId) -- | Similar to nameQuery but if the named process doesn't exist, it -- will be started from the given closure. If the process is already -- running, the closure will be ignored. nameQueryOrStart :: NodeId -> String -> Closure (ProcessM ()) -> ProcessM ProcessId -- | Establishes bidirectional abnormal termination monitoring between the -- current process and another. Monitoring established with linkProcess -- is bidirectional and signals only in the event of abnormal -- termination. In other words, linkProcess a is equivalent to: -- --
--   monitorProcess mypid a MaLinkError
--   monitorProcess a mypid MaLinkError
--   
linkProcess :: ProcessId -> ProcessM () -- | Establishes unidirectional processing of another process. The format -- is: -- --
--   monitorProcess monitor monitee action
--   
-- -- Here, -- -- -- -- Monitoring will remain in place until one of the processes ends or -- until unmonitorProcess is called. Calls to -- monitorProcess are cumulative, such that calling -- monitorProcess 3 three times on the same pair of processes will -- ensure that monitoring will stay in place until -- unmonitorProcess is called three times on the same pair of -- processes. If the monitee is not currently running, the monitor will -- be signalled immediately. See also MonitorAction. monitorProcess :: ProcessId -> ProcessId -> MonitorAction -> ProcessM () -- | Removes monitoring established by monitorProcess. Note that the -- type of monitoring, given in the third parameter, must match in order -- for monitoring to be removed. If monitoring has not already been -- established between these two processes, this function takes not -- action. unmonitorProcess :: ProcessId -> ProcessId -> MonitorAction -> ProcessM () -- | Establishes temporary monitoring of another process. The process to be -- monitored is given in the first parameter, and the code to run in the -- second. If the given process goes down while the code in the second -- parameter is running, a process down message will be sent to the -- current process, which can be handled by matchProcessDown. withMonitor :: ProcessId -> ProcessM a -> ProcessM a -- | The different kinds of monitoring available between processes. data MonitorAction -- | MaMonitor means that the monitor process will be sent a -- ProcessDownException message when the monitee terminates for any -- reason. MaMonitor :: MonitorAction -- | MaLink means that the monitor process will receive an asynchronous -- exception of type ProcessDownException when the monitee terminates for -- any reason MaLink :: MonitorAction -- | MaLinkError means that the monitor process will receive an -- asynchronous exception of type ProcessDownException when the monitee -- terminates abnormally MaLinkError :: MonitorAction -- | The main form of notification to a monitoring process that a monitored -- process has terminated. This data structure can be delivered to the -- monitor either as a message (if the monitor is of type -- MaMonitor) or as an asynchronous exception (if the monitor is -- of type MaLink or MaLinkError). It contains the PID of -- the monitored process and the reason for its nofication. data ProcessMonitorException ProcessMonitorException :: ProcessId -> SignalReason -> ProcessMonitorException -- | Returns information about all nodes on the current network that this -- node knows about. This function combines dynamic and static -- mechanisms. See documentation on getPeersStatic and -- getPeersDynamic for more info. This function depends on the -- configuration values cfgKnownHosts and -- cfgPeerDiscoveryPort. getPeers :: ProcessM PeerInfo -- | Given a PeerInfo returned by getPeersDynamic or getPeersStatic, give a -- list of nodes registered as a particular role. If no nodes of that -- role are found, the empty list is returned. findPeerByRole :: PeerInfo -> String -> [NodeId] -- | Created by Remote.Peer.getPeers, this maps each role to a -- list of nodes that have that role. It can be examined directly or -- queried with findPeerByRole. type PeerInfo = Map String [NodeId] -- | A compile-time macro to provide easy invocation of closures. To use -- this, follow the following steps: -- --
    --
  1. First, enable Template Haskell in the module:
  2. --
-- --
--   {-# LANGUAGE TemplateHaskell #-}
--   module Main where
--   import Remote.Call (remotable)
--      ...
--   
-- --
    --
  1. Define your functions normally. Restrictions: function's type -- signature must be explicitly declared; no polymorphism; all parameters -- must implement Serializable; return value must be pure, or in one of -- the ProcessM, TaskM, or IO monads; probably other -- restrictions as well.
  2. --
-- --
--   greet :: String -> ProcessM ()
--   greet name = say ("Hello, "++name)
--   badFib :: Integer -> Integer
--   badFib 0 = 1
--   badFib 1 = 1
--   badFib n = badFib (n-1) + badFib (n-2)
--   
-- --
    --
  1. Use the remotable function to automagically generate stubs -- and closure generators for your functions:
  2. --
-- --
--   $( remotable ['greet, 'badFib] )
--   
-- -- remotable may be used only once per module. -- --
    --
  1. When you call remoteInit (usually the first thing in your -- program), be sure to give it the automagically generated function -- lookup tables from all modules that use remotable:
  2. --
-- --
--   main = remoteInit (Just "config") [Main.__remoteCallMetaData, OtherModule.__remoteCallMetaData] initialProcess
--   
-- --
    --
  1. Now you can invoke your functions remotely. When a function -- expects a closure, give it the name of the generated closure, rather -- than the name of the original function. If the function takes -- parameters, so will the closure. To start the greet function -- on someNode:
  2. --
-- --
--   spawn someNode (greet__closure "John Baptist")
--   
-- -- Note that we say greet__closure rather than just -- greet. If you prefer, you can use mkClosure instead, -- i.e. $(mkClosure 'greet), which will expand to -- greet__closure. To calculate a Fibonacci number remotely: -- --
--   val <- callRemotePure someNode (badFib__closure 5)
--   
remotable :: [Name] -> Q [Dec] -- | Data of this type is generated at compile-time by remotable -- and can be used with registerCalls and remoteInit to -- create a metadata lookup table, Lookup. The name -- __remoteCallMetaData will be present in any module that uses -- remotable. type RemoteCallMetaData = Lookup -> Lookup data Lookup -- | A data type representing a closure, that is, a function with its -- environment. In spirit, this is actually: -- --
--   data Closure a where
--     Closure :: Serializable v => Static (v -> a) -> v -> Closure a     
--   
-- -- where the Static type wraps a function with no non-static free -- variables. We simulate this behavior by identifying top-level -- functions as strings. See the paper for clarification. data Closure a makeClosure :: (Typeable a, Serializable v) => String -> v -> ProcessM (Closure a) invokeClosure :: Typeable a => Closure a -> ProcessM (Maybe a) data Payload -- | Data types that can be used in messaging must be serializable, which -- means that they must implement the get and put methods -- from Binary. If you are too lazy to write these functions -- yourself, you can delegate responsibility to this function. It's -- usually sufficient to do something like this: -- --
--   import Data.Data (Data)
--   import Data.Typeable (Typeable)
--   import Data.Binary (Binary, get, put)
--   data MyType = MkMyType Foobar Int [(String, Waddle Baz)]
--               | MkSpatula
--                    deriving (Data, Typeable)
--   instance Binary MyType where
--      put = genericPut
--      get = genericGet
--   
genericPut :: Data a => a -> Put -- | This is the counterpart genericPut genericGet :: Data a => Get a -- | Data that can be sent as a message must implement this class. The -- class has no functions of its own, but instead simply requires that -- the type implement both Typeable and Binary. Typeable -- can usually be derived automatically. Binary requires the put and get -- functions, which can be easily implemented by hand, or you can use the -- genericGet and genericPut flavors, which will work -- automatically for types implementing Data. class (Binary a, Typeable a) => Serializable a -- | A channel is a unidirectional communication pipeline with two ends: a -- sending port, and a receiving port. This is the sending port. A -- process holding this value can insert messages into the channel. -- SendPorts themselves can also be sent to other processes. The other -- side of the channel is the ReceivePort. data SendPort a -- | A process holding a ReceivePort can extract messages from the channel, -- which we inserted by the holder(s) of the corresponding -- SendPort. Critically, ReceivePorts, unlike SendPorts, are not -- serializable. This means that you can only receive messages through a -- channel on the node on which the channel was created. data ReceivePort a -- | Create a new channel, and returns both the SendPort and -- ReceivePort thereof. newChannel :: Serializable a => ProcessM (SendPort a, ReceivePort a) -- | Inserts a new value into the channel. sendChannel :: Serializable a => SendPort a -> a -> ProcessM () -- | Extract a value from the channel, in FIFO order. receiveChannel :: Serializable a => ReceivePort a -> ProcessM a data CombinedChannelAction b -- | Specifies a port and an adapter for combining ports via -- combinePortsBiased and combinePortsRR. combinedChannelAction :: Serializable a => ReceivePort a -> (a -> b) -> CombinedChannelAction b -- | This function lets us respond to messages on multiple channels by -- combining several ReceivePorts into one. The resulting port is -- the sum of the input ports, and will extract messages from all of them -- in FIFO order. The input ports are specified by -- combinedChannelAction, which also gives a converter function. -- After combining the underlying receive ports can still be used -- independently, as well. We provide two ways to combine ports, which -- differ bias they demonstrate in returning messages when more than one -- underlying channel is nonempty. combinePortsBiased will check ports in -- the order given by its argument, and so if the first channel always -- was a message waiting, it will. starve the other channels. The -- alternative is combinePortsRR. combinePortsBiased :: Serializable b => [CombinedChannelAction b] -> ProcessM (ReceivePort b) -- | See combinePortsBiased. This function differs from that one in -- that the order that the underlying ports are checked is rotated with -- each invocation, guaranteeing that, given enough invocations, every -- channel will have a chance to contribute a message. combinePortsRR :: Serializable b => [CombinedChannelAction b] -> ProcessM (ReceivePort b) -- | Similar to combinePortsBiased, with the difference that the the -- underlying ports must be of the same type, and you don't have the -- opportunity to provide an adapter function. mergePortsBiased :: Serializable a => [ReceivePort a] -> ProcessM (ReceivePort a) -- | Similar to combinePortsRR, with the difference that the the -- underlying ports must be of the same type, and you don't have the -- opportunity to provide an adapter function. mergePortsRR :: Serializable a => [ReceivePort a] -> ProcessM (ReceivePort a) -- | Terminate a channel. After calling this function, -- receiveChannel on that port (or on any combined port based on -- it) will either fail or block indefinitely, and sendChannel on -- the corresponding SendPort will fail. Any unread messages -- remaining in the channel will be lost. terminateChannel :: Serializable a => ReceivePort a -> ProcessM () data TaskM a -- | Starts a new context for executing a TaskM environment. The -- node on which this function is run becomes a new master in a Task -- application; as a result, the application should only call this -- function once. The master will attempt to control all nodes that it -- can find; if you are going to be running more than one CH application -- on a single network, be sure to give each application a different -- network magic (via cfgNetworkMagic). The master TaskM environment -- created by this function can then spawn other threads, locally or -- remotely, using newPromise and friends. runTask :: TaskM a -> ProcessM a -- | The basic data type for expressing data dependence in the TaskM -- monad. A Promise represents a value that may or may not have been -- computed yet; thus, it's like a distributed thunk (in the sense of a -- non-strict unit of evaluation). These are created by newPromise -- and friends, and the underlying value can be gotten with -- readPromise. data Promise a -- | Given a function (expressed here as a closure, see Remote.Call) -- that computes a value, returns a token identifying that value. This -- token, a Promise can be moved about even if the value hasn't -- been computed yet. The computing function will be started somewhere -- among the nodes visible to the current master, preferring those nodes -- that correspond to the defaultLocality. Afterwards, attempts to -- redeem the promise with readPromise will contact the node where -- the function is executing. newPromise :: Serializable a => Closure (TaskM a) -> TaskM (Promise a) -- | A variant of newPromise that prefers to start the computing -- function on the same node as the caller. Useful if you plan to use the -- resulting value locally. newPromiseHere :: Serializable a => Closure (TaskM a) -> TaskM (Promise a) -- | A variant of newPromise that prefers to start the computing -- functions on some set of nodes that have a given role (assigned by the -- cfgRole configuration option). newPromiseAtRole :: Serializable a => String -> Closure (TaskM a) -> TaskM (Promise a) -- | A variant of newPromise that prefers to start the computing -- function on the same node where some other promise lives. The other -- promise is not evaluated. newPromiseNear :: (Serializable a, Serializable b) => Promise b -> Closure (TaskM a) -> TaskM (Promise a) -- | Like newPromise, but creates a promise whose values is already -- known. In other words, it puts a given, already-calculated value in a -- promise. Conceptually (but not syntactically, due to closures), you -- can consider it like this: -- --
--   toPromise a = newPromise (return a)
--   
toPromise :: Serializable a => a -> TaskM (Promise a) -- | Similar to toPromiseAt and newPromiseNear toPromiseNear :: (Serializable a, Serializable b) => Promise b -> a -> TaskM (Promise a) -- | Creates an immediate promise, which is to say, a promise in -- name only. Unlike a regular promise (created by toPromise), -- this kind of promise contains the value directly. The advantage is -- that promise redemption is very fast, requiring no network -- communication. The downside is that it the underlying data will be -- copied along with the promise. Useful only for small data. toPromiseImm :: Serializable a => a -> TaskM (Promise a) -- | Given a promise, gets the value that is being calculated. If the -- calculation has finished, the owning node will be contacted and the -- data moved to the current node. If the calculation has not finished, -- this function will block until it has. If the calculation failed by -- throwing an exception (e.g. divide by zero), then this function will -- throw an excption as well (a TaskException). If the node owning -- the promise is not accessible, the calculation will be restarted. readPromise :: Serializable a => Promise a -> TaskM a -- | Writes various kinds of messages to the Remote.Process log. tlogS :: LogSphere -> LogLevel -> String -> TaskM () -- | A Task-monadic version of say. Puts text messages in the log. tsay :: String -> TaskM () data TaskException TaskException :: String -> TaskException -- | A data structure that stores the important user-provided functions -- that are the namesakes of the MapReduce algorithm. The number of -- mapper processes can be controlled by the user by controlling the -- length of the string returned by mtChunkify. The number of reducer -- promises is controlled by the number of values values returned by -- shuffler. The user must provide their own mapper and reducer. For many -- cases, the default chunkifier (chunkify) and shuffler -- (shuffle) are adequate. data MapReduce rawinput input middle1 middle2 result MapReduce :: (input -> Closure (TaskM [middle1])) -> (middle2 -> Closure (TaskM result)) -> (rawinput -> [input]) -> ([middle1] -> [middle2]) -> MapReduce rawinput input middle1 middle2 result mtMapper :: MapReduce rawinput input middle1 middle2 result -> input -> Closure (TaskM [middle1]) mtReducer :: MapReduce rawinput input middle1 middle2 result -> middle2 -> Closure (TaskM result) mtChunkify :: MapReduce rawinput input middle1 middle2 result -> rawinput -> [input] mtShuffle :: MapReduce rawinput input middle1 middle2 result -> [middle1] -> [middle2] -- | The MapReduce algorithm, implemented in a very simple form on top of -- the Task layer. Its use depends on four user-determined data types: -- -- mapReduce :: (Serializable i, Serializable k, Serializable m, Serializable r) => MapReduce ri i k m r -> ri -> TaskM [r] -- | A convenient way to provide the mtChunkify function as part of -- mapReduce. chunkify :: Int -> [a] -> [[a]] -- | A convenient way to provide the mtShuffle function as part of -- mapReduce. shuffle :: Ord a => [(a, b)] -> [(a, [b])]