rR       !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~               2Data that can be sent as a message must implement 4 this class. The class has no functions of its own, 5 but instead simply requires that the type implement  both  and . Typeable can usually ; be derived automatically. Binary requires the put and get 5 functions, which can be easily implemented by hand,  or you can use the  and  flavors, 6 which will work automatically for types implementing  .  .Data types that can be used in messaging must 7 be serializable, which means that they must implement  the  and  methods from  . If you 1 are too lazy to write these functions yourself, 3 you can delegate responsibility to this function.  It'0s 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 This is the counterpart       NA data type representing a closure, that is, a function with its environment.  In spirit, this is actually:   data Closure a where I Closure :: Serializable v => Static (v -> a) -> v -> Closure a Jwhere the Static type wraps a function with no non-static free variables. L We simulate this behavior by identifying top-level functions as strings. $ See the paper for clarification. /Data of this type is generated at compile-time  by  remotable and can be used with   and  remoteInit$ to create a metadata lookup table, .  The name __remoteCallMetaData will be present  in any module that uses  remotable. @Creates a metadata lookup table based on compile-time metadata.  You probably don'3t want to call this function yourself, but instead  use Remote.Init.remoteInit. w !"#$%&'()*+ Created by Remote.Peer.getPeers , this maps 3 each role to a list of nodes that have that role. - It can be examined directly or queried with  findPeerByRole. ,-. !/012"_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 ,=) or as an asynchronous exception (if the monitor is of type + or *). Q It contains the PID of the monitored process and the reason for its nofication. #345678$ePart of the notification system of process monitoring, indicating why the monitor is being notified. %ZSrInvalid: the monitee was not running at the time of the attempt to establish monitoring &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. 'Nthe monitee terminated with an uncaught exception, which is given as a string ( the monitee terminated normally )?The different kinds of monitoring available between processes. *MaLinkError means that the monitor process will receive an asynchronous exception of type ProcessDownException when the monitee terminates abnormally +MaLink means that the monitor process will receive an asynchronous exception of type ProcessDownException when the monitee terminates for any reason ,MaMonitor means that the monitor process will be sent a ProcessDownException message when the monitee terminates for any reason. 9:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[-1Expresses a current configuration of the logging 4 subsystem, which determines which log messages to 1 be output and where to send them when they are. 3 Both processes and nodes have log configurations,  set with  and  - respectively. The node log configuration is 1 used for all processes that have not explicitly - set their log configuration. Otherwise, the + process log configuration takes priority. ./3The lowest message priority that will be displayed 0Where to send messages 1Other filtering 2.Specifies which log messages will be output. 2 All log messages of importance below the current 0 log level or not among the criterea given here . will be suppressed. This type lets you limit / displayed log messages to certain components. 34562A preference as to what is done with log messages 7Special value -- don't set this in your LogConfig! 80Log messages will be appended to the given file 9<Log messages will be forwarded to the given node; please don't set up a loop :4Messages will be output to the console; the default ;:Specifies the subsystem or region that is responsible for = generating a given log entry. This is useful in conjunction  with 2& to limit displayed log output to the C particular area of your program that you are currently debugging. 9 The SYS, TSK, and SAY spheres are used by the framework = for messages relating to the Process layer, the Task layer,  and the  function. D The remainder of values are free for use at the application level. <4Specifies the importance of a particular log entry. ( Can also be used to filter log output. =>?The default log level @ABC,Non-suppressible application-level emission \]^_`DEFGHIJKLMNOPQaUsed internally by ! to mark the orderly termination  of a process bR Thrown by Remote.Process system services in response  to some problem ST Thrown by  in response to a message - of a wrong type being received by a process UV1Thrown by various network-related functions when & communication with a host has failed Wc*Thrown in response to a bad configuration * file or command line option, most likely  in dc defgX0This monad provides the state and structure for = matching received messages from the incoming message queue.  It's the interface between the { family of functions,  and the * family, which together can express which  messages can be accepted. hiY?The monad ProcessM is the core of the process layer. Functions ? in the ProcessM monad may participate in messaging and create 1 additional concurrent processes. You can create  a ProcessM context from an j context with the  remoteInit function. klZmno[pqrstuvwxyz{|}~\]^_`5Identifies a process somewhere on the network. These  are produced by the  family of functions and  consumed by &. When a process ends, its process ID  ceases to be valid. See also  a2Identifies a node somewhere on the network. These  can be queried from getPeers . See also  bcYThe Config structure encapsulates the user-settable configuration options for each node. S 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  deThe user-assigned role of this node determines what its initial behavior is and how it presents itself to its peers. Default to NODE fThe 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. glThe TCP port on which to listen to for new connections. If unassigned or 0, the OS will assign a free port. hpThe TCP port on which to communicate with the local node registry, or to start the local node registry if it isn'5t already running. This defaults to 38813 and shouldn'8t be changed unless you have prohibitive firewall rules iThe UDP port on which local peer discovery broadcasts are sent. Defaults to 38813, and only matters if you rely on dynamic peer discovery jThe 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 k1A list of hosts where nodes may be running. When Remote.Peer.getPeers or Remote.Peer.getPeerStaticu is called, each host on this list will be queried for its nodes. Only matters if you rely on static peer discovery. lMicroseconds 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). mDA limit on the number of simultaneous outgoing connections per node ngTime in microseconds before an in-memory promise is flushed to disk. 0 to disable disk flush entirely. o/Prepended to the filename of flushed promises. p{Command-line arguments that are not part of the node configuration are placed here and can be examined by your application $ logConfig :: LogConfig qrstuv/Returns command-line arguments provided to the 2 executable, excluding any command line arguments ' that were processed by the framework. wxyz{]Examines the message queue of the current process, matching each message against each of the M provided message pattern clauses (typically provided by a function from the  family). If [ a message matches, the corresponding handler is invoked and its result is returned. If no ' message matches, Nothing is returned. |#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 { family of functions, ) this function does not allow the notion " of choice in message extraction. }]Examines the message queue of the current process, matching each message against each of the M provided message pattern clauses (typically provided by a function from the  family). If [ a message matches, the corresponding handler is invoked and its result is returned. If no L message matches, the function blocks until a matching message is received. ~]Examines the message queue of the current process, matching each message against each of the M provided message pattern clauses (typically provided by a function from the  family). If [ a message matches, the corresponding handler is invoked and its result is returned. If no Y message matches, the function blocks until a matching message is received, or until the T specified time in microseconds has elapsed, at which point it will return Nothing. < If the specified time is 0, this function is equivalent to {. A catch-all variant of % that invokes user-provided code and E will extact any message from the queue. This is useful for matching K against messages that are not recognized. Since message matching patterns L are evaluated in order, this function, if used, should be the last element " in the list of matchers given to } and similar functions.  A variant of  that throws a UT + if the process receives a message that isn'(t extracted by another message matcher.  Equivalent to: 6 matchUnknown (throw (UnknownMessageException "...")) %Used to specify a message pattern in } 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 1, will be removed from the queue, at which point - the user-provided function will be invoked.  Similar to P, 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  Creates a new b? object, given the specified configuration (usually created by ) and , function metadata table (usually create by Remote.Call.registerCalls). You probably want to use  Remote.Init.remoteInit' instead of this lower-level function. Given a Node (created by )), start execution of user-provided code - by invoking the given function with the node's e string. FStart executing a process on the current node. This is a variation of  @ which accepts two blocks of user-defined code. The first block I is the main body of the code to run concurrently. The second block is a prefix M which is run in the new process, prior to the main body, but its completion L is guaranteed before spawnAnd returns. Thus, the prefix code is useful for - initializing the new process synchronously. A synonym for  BCreate a parallel process sharing the same message queue and PID. C Not safe for export, as doing any message receive operation could $ result in a munged message queue. ACreate a new process on the current node. Returns the new process's identifier.  Unlike  , this function does not need a  or a a. -Sends a message to the given process. If the  process isn't running or can't be accessed,  this function will throw a WV.  The message must implement the  interface. Like 9, but in case of error returns a value rather than throw  an exception. AStarts a message-receive loop on the given node. You probably don''t want to call this function yourself. 5Blocks until all non-daemonic processes of the given B node have ended. Usually called on the main thread of a program. HReturns the node ID of the node that the current process is running on. /Returns the process ID of the current process. JReturns true if the given process ID is associated with the current node. 7 Does not examine if the process is currently running. A Y-flavoured variant of  A Y-flavoured variant of  A Y-flavoured variant of  A Y-flavoured variant of  `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 7 then it should be the name of the configuration file; C 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, 6 which also takes into account environment variables. E Options set by command-line parameters have the highest precedence, a 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 b 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. I ./MyProgram -cfgHostName=host3 -cfgKnownHosts='host1 host2 host3 host4' )The default log configuration represents ' a starting point for setting your own  configuration. It is:  logLevel = LoStandard  logTarget = LtStdout  logFilter = LfAll QUses the logging facility to produce non-filterable, programmatic output. Shouldn' t be used E for informational logging, but rather for application-level output. ,Gets the currently active log configuration 1 for the current process; if the current process  doesn'+t have a log configuration set, the process's $ log configuration will be returned Set the process'$s log configuration. This overrides " any node-level log configuration  Sets the node's log configuration -Sets the log configuration of a remote node.  May throw TransmitException (Generates a log entry, using the process'!s current logging configuration.  ;c indicates the subsystem generating this message. SYS in the case of componentes of the framework.  <* indicates the importance of the message. ) The third parameter is the log message. CBoth of the first two parameters may be used to filter log output. >Sends a small message to the specified node to determine if it' s alive. U If the node cannot be reached or does not respond within a time frame, the function  will return False.  Similar to  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. 7Query the PID of a named process on a particular node. / If no process of that name exists, or if that 3 process has ended, this function returns Nothing. @Assigns a name to the current process. The name is local to the C 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 1 with the name on a single node, it will throw a SR. 6 The PID of a named process can be queried later with  . When the ; named process ends, its name will again become available. B One reason to use named processes is to create node-local state. D 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 1 [ match (\newcolor -> return newcolor), : match (\pid -> send pid color >> return color)  ] >>= loop  4 setFavoriteColor :: NodeId -> Color -> ProcessM ()  setFavoriteColor nid color = 2 do (Just pid) <- nameQuery nid "favorite_color"  send pid color  . getFavoriteColor :: NodeId -> ProcessM Color  getFavoriteColor nid = 2 do (Just pid) <- nameQuery nid "favorite_color"  mypid <- getSelfPid  send pid mypid  expect NEstablishes bidirectional abnormal termination monitoring between the current > process and another. Monitoring established with linkProcess I 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 A specialized version of  (for use with {, }( and friends) for catching process down n messages. This way processes can avoid waiting forever for a response from another process that has crashed.  Intended to be used within a  block, e.g.:  withMonitor apid $  do send apid QueryMsg  receiveWait  [ + match (\AnswerMsg -> return "ok"), 4 matchProcessDown apid (return "aborted")  ] aEstablishes temporary monitoring of another process. The process to be monitored is given in the c first parameter, and the code to run in the second. If the given process goes down while the code a in the second parameter is running, a process down message will be sent to the current process,  which can be handled by . IEstablishes unidirectional processing of another process. The format is:  ' monitorProcess monitor monitee action Here, G monitor is the process that will be notified if the monitee goes down / monitee is the process that will be monitored 4 action determines how the monitor will be notified IMonitoring will remain in place until one of the processes ends or until   is called. Calls to  are cumulative,  such that calling - 3 three times on the same pair of processes 6 will ensure that monitoring will stay in place until  is called , three times on the same pair of processes. U If the monitee is not currently running, the monitor will be signalled immediately.  See also ). "Removes monitoring established by . Note that the type of N monitoring, given in the third parameter, must match in order for monitoring M to be removed. If monitoring has not already been established between these 0 two processes, this function takes not action. MStart a process running the code, given as a closure, on the specified node. L If successful, returns the process ID of the new process. If unsuccessful,  throw a WV. /Ends the current process in an orderly manner. <If a remote process has been started in a paused state with  , N it will be running but inactive until unpaused. Use this function to unpause L such a function. It has no effect on processes that are not paused or that  have already been unpaused.  A variant of % that starts the remote process with ! bidirectoinal monitoring, as in   A variant of E that allows greater control over how the remote process is started. :Invokes a function on a remote node. The function must be ? given by a closure. This function will block until the called 1 function completes or the connection is broken. BEvery 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. IContacts 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 KContacts 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 JContacts the local node registry and attempts to verify that it is alive. N If the local node registry cannot be contacted, an exception will be thrown.  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~϶Ya`|X{}~;<CBA@?>=6:9872543-./01TURSVWDQPONMLKJIHGFE !),+*$('&%"#cdefghijklmnopwvzrqyu\Z[[x]_^bts ! !"##$('&%%&'(),+**+,-./01./0125433456:987789:;<CBA@?>==>?@ABCD QPONMLKJIHGFEEFGHIJKLMNOPQRSSTUUVWWXYZ[[\]_^^_`abc defghijklmnopdefghijklmnopqrstuvwxyz{|}~;Returns information about all nodes on the current network < that this node knows about. This function combines dynamic - and static mechanisms. See documentation on   and & for more info. This function depends  on the configuration values  cfgKnownHosts and cfgPeerDiscoveryPort. FReturns a PeerInfo, containing a list of known nodes ordered by role. E 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'3t respond are assumed to be down and nodes running  on them won't be included in the results. FReturns a PeerInfo, containing a list of known nodes ordered by role. D 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. I If nodes are running outside of the local network, or if UDP broadcasts 1 are disabled by firewall configuration, this won't return useful 0 information; in that case, use getPeersStatic. F This function takes a parameter indicating how long in microseconds K to wait for hosts to respond. A number like 50000 is usually good enough, ? unless your network is highly congested or with high latency. @Given a PeerInfo returned by getPeersDynamic or getPeersStatic, F give a list of nodes registered as a particular role. If no nodes of 2 that role are found, the empty list is returned. ?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 +A data structure that stores the important 0 user-provided functions that are the namesakes  of the MapReduce algorithm. 2 The number of mapper processes can be controlled 5 by the user by controlling the length of the string / returned by mtChunkify. The number of reducer 0 promises is controlled by the number of values  values returned by shuffler. 5 The user must provide their own mapper and reducer. ) For many cases, the default chunkifier ()  and shuffler () are adequate. A specification of preference ) of where a promise should be allocated, ( among the nodes visible to the master. "The given nodes will be preferred /Nodes having the given roles will be preferred VThe default preference is applied, which is for nodes having a role of NODE of WORKER $The promise can be placed anywhere. (Currently ignored.)      -Promise IDs are allocated serially from here iAll currently known nodes, with the role, node ID, and node boss. Updated asychronously by prober thread NGiven a nodeboss, which promises belong to it. Not sure what this is good for  jGiven a promise, what do we know about it. Include its nodeboss, its closure, and its locality preference !HThe locality preference of new worker tasks, if not specified otherwise ">Keeps track of what we know about currently running promises. > The closure and locality and provided by the initial call to < newPromise, the nodeboss is where it is currently running. , We need this info to deal with complaints. #$%5Stores the data produced by a promise, in one of its  various forms. If it'"s currently in memory, we keep it 7 as a payload, to be decoded by its ultimate user (who 6 of course has the static type information), the time 4 it was last touched (so we know when to flush it), 5 and perhaps also a decoded version, so that it doesn't 9 need to be decoded repeatedly: this makes this go a lot  faster. If it')s been flushed to disk, we keep track of  where, and if the promise didn't complete, but threw 7 an exception during its execution, we mark there here . as well: the exception will be propagated to  dependents. &'(3The basic data type for expressing data dependence  in the * monad. A Promise represents a value that 0 may or may not have been computed yet; thus, it's like 8 a distributed thunk (in the sense of a non-strict unit & of evaluation). These are created by  and friends, - and the underlying value can be gotten with . )*+,-./0123456789:;<=>?@A%Starts a new context for executing a  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, 6 be sure to give each application a different network ; magic (via cfgNetworkMagic). The master TaskM environment 8 created by this function can then spawn other threads,  locally or remotely, using  and friends. BCDEFGHLike , but creates a promise whose 2 values is already known. In other words, it puts 1 a given, already-calculated value in a promise. 8 Conceptually (but not syntactically, due to closures),  you can consider it like this: % toPromise a = newPromise (return a)  A variant of  that lets the user 6 express a locality preference, i.e. some information / about which node will become the owner of the 5 new promise. These preferences will not necessarily  be respected.  Similar to  and   Creates an immediate promise, which is to say, a promise 4 in name only. Unlike a regular promise (created by ), 8 this kind of promise contains the value directly. The > advantage is that promise redemption is very fast, requiring 7 no network communication. The downside is that it the 8 underlying data will be copied along with the promise.  Useful only for small data. 3Given a function (expressed here as a closure, see  Remote.Call) @ that computes a value, returns a token identifying that value.  This token, a  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 8 current master, preferring those nodes that correspond  to the 0. Afterwards, attempts to  redeem the promise with  will contact the node " where the function is executing.  A variant of  that prefers to start 8 the computing function on the same node as the caller. / Useful if you plan to use the resulting value  locally.  A variant of  that prefers to start 4 the computing function on the same node where some / other promise lives. The other promise is not  evaluated.  A variant of  that prefers to start 3 the computing functions on some set of nodes that : have a given role (assigned by the cfgRole configuration  option).  A variant of  that lets the user  specify a #. The other flavors of newPromise,  such as , , and  0 at just shorthand for a call to this function. .Given a promise, gets the value that is being . calculated. If the calculation has finished, 0 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 1 by throwing an exception (e.g. divide by zero), 3 then this function will throw an excption as well  (a ). If the node owning the , promise is not accessible, the calculation  will be restarted. IJKLMNOA Task-monadic version of .  Puts text messages in the log. (Writes various kinds of messages to the  Remote.Process log.  A convenient way to provide the  function  as part of .  A convenient way to provide the  function  as part of . /The MapReduce algorithm, implemented in a very + simple form on top of the Task layer. Its 1 use depends on four user-determined data types: c input -- The data type provided as the input to the algorithm as a whole and given to the mapper. < middle1 -- The output of the mapper. This may include some key= which is used by the shuffler to allocate data to reducers. " If you use the default shuffler, , this type must have the form Ord a => (a,b). V middle2 -- The output of the shuffler. The default shuffler emits a type in the form  Ord => (a,[b]). Each middle2 output - by shuffler is given to a separate reducer. K result -- The output of the reducer, upon being given a bunch of middles. %%%PQRSTUVWXYZDA 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 7 as addressing the closure generator by name, that is,   foo__closure$. In some cases you may need to use   instead.  A variant of ! 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 8 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  with each function ) that may be an argument of mkClosureRec [\]^_`abcdefgh=A compile-time macro to provide easy invocation of closures. * To use this, follow the following steps:  / First, enable Template Haskell in the module:  " {-# LANGUAGE TemplateHaskell #-}  module Main where  import Remote.Call (remotable)  ...  7 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 Y, , or j. monads; probably other restrictions as well.   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)   Use the U function to automagically generate stubs and closure generators for your functions:  " $( remotable ['greet, 'badFib] ) # may be used only once per module.   When you call  remoteInit- (usually the first thing in your program), G be sure to give it the automagically generated function lookup tables  from all modules that use :  p main = remoteInit (Just "config") [Main.__remoteCallMetaData, OtherModule.__remoteCallMetaData] initialProcess  a Now you can invoke your functions remotely. When a function expects a closure, give it the name l 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:  0 spawn someNode (greet__closure "John Baptist") Note that we say greet__closure rather than just greet. If you prefer, you can use  instead, i.e.  $(mkClosure 'greet), which will expand to greet__closure,. To calculate a Fibonacci number remotely: 4 val <- callRemotePure someNode (badFib__closure 5) ijklCThis is the usual way create a single node of distributed program.  The intent is that  be called in your program's  Main.main + function. A typical call takes this form:  N main = remoteInit (Just "config") [Main.__remoteCallMetaData] initialProcess  This will:  Read the configuration file configj in the current directory or, if specified, from the file whose path is given by the environment variable  RH_CONFIGO. If the given file does not exist or is invalid, an exception will be thrown.  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. % Compile-time metadata, generated by Remote.Call.remotable[, will used for invoking closures. Metadata from each module must be explicitly mentioned.  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.  m5A process holding a ReceivePort can extract messages ( from the channel, which we inserted by $ the holder(s) of the corresponding . C Critically, ReceivePorts, unlike SendPorts, are not serializable. A This means that you can only receive messages through a channel / on the node on which the channel was created. nop5A channel is a unidirectional communication pipeline 6 with two ends: a sending port, and a receiving port. 2 This is the sending port. A process holding this 7 value can insert messages into the channel. SendPorts 1 themselves can also be sent to other processes. & The other side of the channel is the . q+Create a new channel, and returns both the   and  thereof. &Inserts a new value into the channel. 1Extract a value from the channel, in FIFO order. r8Specifies a port and an adapter for combining ports via  and  . ?This function lets us respond to messages on multiple channels  by combining several s into one. The resulting port C is the sum of the input ports, and will extract messages from all : of them in FIFO order. The input ports are specified by  ), which also gives a converter function. 8 After combining the underlying receive ports can still ! be used independently, as well. 9 We provide two ways to combine ports, which differ bias ; they demonstrate in returning messages when more than one 9 underlying channel is nonempty. combinePortsBiased will 8 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 . See &. This function differs from that one D in that the order that the underlying ports are checked is rotated D with each invocation, guaranteeing that, given enough invocations, ; every channel will have a chance to contribute a message.  Similar to , with the difference that the ; the underlying ports must be of the same type, and you don't 6 have the opportunity to provide an adapter function.  Similar to , with the difference that the ; the underlying ports must be of the same type, and you don't 6 have the opportunity to provide an adapter function. st 2Terminate a channel. After calling this function,  A on that port (or on any combined port based on it) will either ! fail or block indefinitely, and  on the corresponding  9 will fail. Any unread messages remaining in the channel  will be lost.     !"#)*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXY`av{|}~ Ya`X !|{}~;6:9872543-./01<CBA@?>=vTURSVWDQPONMLKJIHGFE),+*"# u    !"#$%&&'()*++,-./01234556789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYYZZ[[\]^_`abcdefgghijklmnopqrstuvwxyz{|}~                   !!"#$%&'()**+,--..//00123456789:;<=>?@ABCDEEFGHIJKLMNOPQRSTUTVVWXYZZ[[\\]\^_`a]b^cdefghijjkllmnopqrstuvwxydefz{|}~      !"#$%&'()*+,-./01223456789:;<=>?@ABCDEFGHIJKLM  N O P  Q R ST remote-0.1Remote.EncodingRemote.Closure Remote.RegRemote.Process Remote.Peer Remote.Task Remote.Call Remote.InitRemote.ChannelRemote PayloadLengthDynamicPayloadPayload Serializable payloadLengthgetPayloadContentgetPayloadType hPutPayload hGetPayloadserialEncodePuredynamicEncodePuredynamicDecodePuregetDynamicPayloadType serialEncodeserialDecodePure serialDecode genericPut genericGetClosureLookup IdentifierRemoteCallMetaData registerCallsputReggetEntryByIdentemptyPeerInfoAmSpawnOptions amsoPausedamsoLink amsoMonitoramsoNameProcessMonitorException SignalReason SrInvalidSrNoPing SrExceptionSrNormal MonitorAction MaLinkErrorMaLink MaMonitor LogConfiglogLevel logTarget logFilter LogFilter LfExcludeLfOnlyLfAll LogTarget LtForwardedLtFile LtForwardLtStdout LogSphereLogLevel LoTrivial LoInformation LoStandard LoImportant LoCriticalLoFatalLoSayTransmitStatus QteThrottleQteUnknownCommandQteConnectionTimeoutQteLoggingErrorQteDispositionFailedQteEncodingErrorQteNetworkErrorQteBadNetworkMagicQtePleaseSendBodyQteOther QteBadFormat QteUnknownPidQteOKServiceExceptionUnknownMessageExceptionTransmitExceptionMatchMProcessMProcess prNodeRefMessagePayloadDispositionPldAdminPldUser ProcessIdNodeIdNodeConfigcfgRole cfgHostName cfgListenPortcfgLocalRegistryListenPortcfgPeerDiscoveryPortcfgNetworkMagic cfgKnownHostscfgRoundtripTimeoutcfgMaxOutgoingcfgPromiseFlushDelaycfgPromisePrefixcfgArgsLocalProcessIdPortIdgetMessageTypegetMessagePayload getProcess getCfgArgs getConfig getLookupgetNewMessageLocalgetQueueLengthreceiveexpect receiveWaitreceiveTimeout matchUnknownmatchUnknownThrowmatchmatchIf matchCondinitNode roleDispatch spawnLocalAnd forkProcess spawnLocalrunLocalProcessroundtripQueryMultiroundtripQueryroundtripQueryUnsaferoundtripQueryImplroundtripResponseroundtripResponseAsyncsend sendQuiet sendSimpleforkAndListenAndDeliverwaitForThreadsdiffTimenullPid getSelfNode getSelfPid nodeFromPidmakeNodeFromHost localFromPid hostFromNid isPidLocalsuppressTransmitExceptionptryptimeoutpbracketpfinally emptyConfig readConfigdefaultLogConfigsay getLogConfig setLogConfigsetNodeLogConfigsetRemoteNodeLogConfiglogSstartLoggingServicepingNodestartNodeMonitorServicestartFinalizerServiceperformFinalization setDaemonicstartProcessRegistryServicenameQueryOrStart nameQuerynameSet linkProcessmatchProcessDown withMonitormonitorProcessunmonitorProcessstartProcessMonitorServicedefaultSpawnOptionsspawn terminateunpause spawnLinkspawnAnd callRemote callRemoteIOcallRemotePurestartSpawnerServicestandaloneLocalRegistrylocalRegistryRegisterNodelocalRegistryUnregisterNodelocalRegistryHellolocalRegistryQueryNodesstartLocalRegistry makeClosuremakePayloadClosureevaluateClosure invokeClosuregetPeersgetPeersStaticgetPeersDynamicfindPeerByRolestartDiscoveryService MapReducemtMapper mtReducer mtChunkify mtShuffleTaskMLocalityLcByNodeLcByRole LcDefaultLcUnrestricted TaskExceptionPromise PromiseListPlNilPlChunk serialEncodeA serialDecodeA__remoteCallMetaDatarunTask toPromise toPromiseAt toPromiseNear toPromiseImm newPromisenewPromiseHerenewPromiseNearnewPromiseAtRole newPromiseAt readPromisetsaytlogSshufflechunkify mapReduce mkClosure mkClosureRec remotable remoteInitCombinedChannelAction ReceivePortSendPort newChannel sendChannelreceiveChannelcombinedChannelActioncombinePortsBiasedcombinePortsRRmergePortsBiased mergePortsRRterminateChanneldynamicPayloadContent payloadTypepayloadContentbaseData.Typeable.InternalTypeablebinary-0.5.0.2 Data.BinaryBinary Data.DataDatagetputserializeConstrdeserializeConstridentMapIdentMapEntry entryName entryFunRef makeEntryputEntryQueueLocalProcessMessageLocalNodeHelloLocalNodeResponseErrorLocalNodeResponseOKLocalNodeAnswerLocalNodeQueryLocalNodeUnregisterLocalNodeRegister LocalNodeDataldmRolesLocalProcessNameAmSpawnUnpauseAmCallAmSpawn GlobalDataglLinksglNextIdglSyncsGlLinks GlCommand GlUnmonitor GlMonitor GlSynchronousGlRequestUnmonitoringGlRequestMoniteeingGlRequestMonitoringGlSignal GlNodeDown GlProcessDownProcessRegistryAnswerProcessRegistryErrorProcessRegistryResponseProcessRegistryCommandProcessRegistrySetProcessRegistryQueryProcessRegistryState ServiceIdServiceProcessRegistryServiceProcessMonitorServiceNodeMonitorServiceNodeRegistryServiceSpawner ServiceLogNodeMonitorInformationNodeMonitorNodeDownNodeMonitorSignalNodeMonitorNodeFailureNodeMonitorCommandNodeMonitorPingNodeMonitorStart LogMessageLogUpdateConfigRoundtripHeadermsgheaderConversationIdmsgheaderSendermsgheaderDestinationProcessTerminationExceptionConfigException MatchBlock mbMessage runMatchMghc-prim GHC.TypesIO runProcessMprPidprSelfprThread prChannelprStateprPool prLogConfig ProcessStateprQueueProcessTableEntry pteThread pteChannel pteDeathTpteDeath pteDaemonicDynamicMessagemsgDDisposition msgDHeader msgDPayloadEncodedMessagemsgEDisposition msgEHeader msgEPayloadndProcessTablendAdminProcessTable ndHostName ndListenPortndConfigndLookup ndLogConfigndNodeFinalizerndNodeFinalized ndOutgoingndNextProcessIdAdminProcessTable ProcessTable makeMessagegetMessageHeadergetMessageDisposition getConfigI putProcess returnHaltliftSTMgetMatch getNewMessagegetCurrentMessages matchMessage matchMessagesmessageHandlerGeneratorreceiveWaitImplconvertErrorCallmatchCoreHeaderless matchCoreforkProcessWeak generalPidroundtripQueryLocalroundtripQueryImplSubsendTry sendBasic sendRawLocal sendRawRemotesendRawRemoteImpl writeMessage writeResult readMessagegetProcessTableEntrydeliverlistenAndDelivermessageHandler paddedStringnewConversationId exclusionList hGetLineZhPutStrZbuildPid getNodeIdbuildPidFromNodeIdControl.Exception.BasetrySystem.Timeouttimeoutbracketfinally Data.MaybeNothing processConfigshowLogMessagelogApplyFilterlogI monitorNode adminGetPidadminDeregister adminRegister adminLookupN serviceThreadgdCombineEntry gdAddMonitor gdDelMonitor gdAddMonitee gdDelMoniteeglExpungeProcess gdAddNodewithMonitoringmonitorProcessQuietmonitorProcessImpl sendInterrupttriggerMonitorcallRemoteImpllocalRegistryMagicMagiclocalRegistryMagicRoleremoteRegistryPidlocalRegistryPidlocalRegistryRegisterNodeImpl queueMake queueInsertqueueInsertMulti queueToList queueFromListwithSem DiscoveryInfo discNodeIddiscRole getUdpSocket maxPacket listenUdp sendBroadcastverifyPeerInfowaitForDiscoveryrunTaskM TaskStatetsMaster tsNodeBosstsPromiseCachetsRedeemerForwarding tsMonitoring NodeBossStatensPromiseCachensRedeemerForwardingQueueingQuSmall QuExclusiveQuNoneNmRedeemResponseNmRedeemResponseExceptionNmRedeemResponseUnknownNmRedeemNmStartResponseNmStart TmNewPeerMmComplainResponse MmComplainMmStatusResponseMmStatusMmNewPromiseResponseMmNewPromiseResponseFail MmNewPromise MasterStatemsNextIdmsNodes msAllocation msPromisesmsDefaultLocality PromiseRecord PromiseDataPromiseStoragePromiseException PromiseOnDiskPromiseInMemoryPromiseImmediate PromiseBasic _psRedeemer_psIdHash PromiseIddefaultQueueingdefaultLocality taskError monitorTask roundtripImpl roundtrip spawnDaemonic runWorkerNoderunWorkerNode__implpassthrough__implPlpassthrough__closureupdatePromiseInMemorymakePromiseInMemory forwardLogs hashClosure undiskifydiskifystartNodeWorkerstartNodeManager startMasterselectLocationcountLocations findPeers sendSilent runMasterstubbornlookupForwardedRedeemersetForwardedRedeemerlookupCachedPromiseputPromiseInCache getMasterliftTask liftTaskIOEnv eProcessMeIOeTaskMePayloadeLoceLiftIOeReturneClosure eClosureT closureInfo closureDecsmakeEnvisMonadmonadOfrestOf wrapMonad getReturns countReturns applyArgs isArrowType generateDecl generateDeclsgenerateMetaData putParams getParams startServicesdispatchServices ReceivePortRRReceivePortBiasedReceivePortSimplereceiveChannelImplchannelCheckPidsreceiveChannelSimple