%%% Start of LaTeX Document %%%
\documentstyle[11pt]{article}

% 1in margins at left and right
\oddsidemargin=0in
\evensidemargin=0in
\textwidth=6.25in              % A4 paper is 8.25in wide

% 1in margins at top and bottom
\headheight=0pt
\headsep=0pt
\topmargin=0in
\textheight=9.7in              % A4 paper is 11.7in high

\setlength{\parindent}{0cm}
\setlength{\parskip}{\medskipamount}
\setlength{\itemsep}{\smallskipamount}

\title{Parallel Implementation through Object Graph Rewriting}
\author{John Glauert \\
	{\em jrwg@sys.uea.ac.uk} \\
	School of Information Systems \\
	University of East Anglia \\
	Norwich NR4 7TJ, UK \\
	Tel: +44 603 592671 \\
	Fax: +44 603 507720}
\date{Submitted to PACT 1995}

\newcommand{\sembrac}[1]{[\![ #1 ]\!]}
\newcommand{\infer}[3]
           {\vspace{.2cm}
            \hbox{${\displaystyle {\frac {#1}{#2}}\hspace{.5cm}{#3}}$}
            \vspace{.2cm}}
% New macros
%\input{john-pi-macros}
% Process notation
\newcommand{\parprocs}[2]{{#1}\,|\,{#2}}
\newcommand{\restrict}[1]{\backslash{#1}}
\newcommand{\replicate}[2]{!\,{#2}}
\newcommand{\guardedrep}[3]{!\,({#2} \cdot {#3})}
\newcommand{\recdef}[2]{{\bf rec} {\recvar {#1}} \cdot {#2}}
\newcommand{\guardedrec}[3]{{\bf rec} {\recvar {#1}} \cdot {#2} \cdot
(\,\parprocs {#3} {\recvar {#1}}\,)}
\newcommand{\recvar}[1]{{#1}}
\newcommand{\agtuse}[2]{\recvar {#1} ({#2})}
\newcommand{\agtdef}[3]{\agtuse {#1} {#2} = {#3}}
\newcommand{\inpact}[3]{{#1}({#2}) \cdot {#3}}
\newcommand{\inpacta}[2]{{#1}({#2})}
\newcommand{\outact}[3]{\overline{#1}\,{#2} \cdot {#3}}
\newcommand{\outacta}[2]{\overline{#1}\,{#2}}
\newcommand{\match}[3]{{#1}={#2} \cdot {#3}}
\newcommand{\inaction}{0}
\newcommand{\pair}[2]{{#1}\,{#2}}
\newcommand{\triv}{}
%\input{john-proc-macros}
% New Process notation
\newcommand{\Ppar}[2]{{#1},\;{#2}}
\newcommand{\Pcall}[2]{{#1}\,!\,{#2}}
\newcommand{\Pdef}[2]{{#1}:{#2}}
\newcommand{\Prule}[5]{\Ppar{\Pdef{#1}{#2}}{\Pcall{#1}{#3}} & \rightarrow & \Ppar{\Pdef{#1}{#5}}{#4}}
\newcommand{\PruleChange}[4]{\Ppar{\Pdef{#1}{#2}}{\Pcall{#1}{#3}} & \rightarrow & \Pdef{#1}{#4}}
\newcommand{\PruleSpawn}[4]{\Prule{#1}{#2}{#3}{#4}{#2}}

% Translation representation
\newcommand{\transwhere}[3]{& & {\makebox[1.5cm][l]{where}}
{#1}\;?\;{#2}\;\cdot\;(\,{#3}\,)}
\newcommand{\transand}[3]{& & {\makebox[1.5cm][l]{and}}
{#1}\;?\;{#2}\;\cdot\;(\,{#3}\,)}
\newcommand{\F}{Facile}
\newcommand{\Cham}{Chemical Abstract Machine}
\newcommand{\Lc}{$\lambda$--calculus}
\newcommand{\LC}{$\lambda$--Calculus}
\newcommand{\Lx}{$\lambda$--expression}
\newcommand{\Pc}{$\pi$--calculus}
\newcommand{\PC}{$\pi$--Calculus}
\newcommand{\PPC}{Polyadic $\pi$--Calculus}
\newcommand{\PPc}{polyadic $\pi$--calculus}
\newcommand{\RA}{{\em return-Subress\/} channel}
\newcommand{\Whnf}{weak head-normal form}
% Source representation
\newcommand{\Labs}[2]{\lambda{#1}.\,{#2}}
\newcommand{\Lapp}[2]{{#1}\,{#2}}
\newcommand{\Ltriv}{()}
\newcommand{\Lpair}[2]{({#1},{#2})}
% Translation representation
\newcommand{\transexp}[2]{\sembrac{#1}_{#2}}
\newcommand{\transdef}[3]{\transexp{#1}{#2} & = & {#3}}
% End of macros
\begin{document}
\maketitle
\begin{abstract}
We report on a new computational model for the parallel implementation of declarative languages. The model, known as {\em Object Graph Rewriting}, was developed as an intermediate language, or abstract machine, for the implementation of multi-paradigm languages. The initial focus was on the functional and concurrent language, \F, but the model seems suitable for capturing essential features of concurrent logic programming and object-oriented languages. The intention of the model is to allow all the efficiency of implementation techniques for sequential machines, while not hindering parallel implementation. The model is fine-grain, but larger grains of sequential computation can be extracted from the examples investigated so far.
\end{abstract}



\section{Introduction and Background}

Designers of multi-paradigm languages need to find a common semantic framework in which to unite the paradigms available in the language. At the implementation level it is necessary to consider the characteristics of the computational models concerned. For example: in conventional languages, dataflow, and strict functional languages computation proceeds immediately; lazy functional languages require a demand to say that a computation is needed; computations in concurrent logic languages may block waiting for instantiation of shared variables.

The present work arose out of a study of implementation techniques for
\F~\cite{Facile}, a multi-paradigm programming language which combines functional and concurrent programming in a symmetric fashion. In \F, functions may create channels and spawn processes; a functional expression may compute and send a value on a channel, or may use a value received on a channel. Process scripts take the form of functions. Existing practical implementations of the language~\cite{DistribFacile} use Standard ML to provide the functional part of the language, with concurrency primitives introduced through a library of new system functions. In this implementation the process features of \F\ are mapped to light-weight threads.


The approach taken in the present study has been to develop translations of
both the functional and concurrent features of \F\ into networks of small
processes. In such networks there is a uniform representation of all features of
the language, so that the relative cost of using the concurrent features of \F\ will be much reduced.
The ultimate goal is to exploit the inherent concurrency of the process networks in an
implementation on a parallel machine.

In its pure form, \F\ enhances the \Lc\ with primitives for process spawning and
channel-based communication in the style of CCS \cite{CCS}. Milner using the \Pc\ \cite{Pi} and its polyadic form~\cite{PolyPi} shows that a \Lx\ may be translated to a process network in the
\PPc\ which simulates the \Lx\ \cite{FunAsProcs}. Similar work was done by Leth
\cite{Leth91}.

One approach is to use process notations that are 
close to the \PPC\ \cite{PolyPi} in which communication is channel-based. Translations such as those of Milner may be employed. Such
work is reported in \cite{SemSym} and \cite{Parle92}. In these models the
channels can be thought of as independent entities which act as brokers,
arranging communications between processes. Similar ideas appear in
\cite{MessageBrokers}.

However, in most cases the channels used in the translations mentioned above were
closely associated with a particular process. This process was the only one to
receive messages from the channel, and furthermore, the process would receive
messages from no other channel. In contrast to the channel-based 
communication of CCS, and the \Pc, a model was developed in which communicating agents use 
process-based, or point-to-point, communication.

The new model of {\em Object Graph Rewriting\/} (OGre) can be seen as a very minimal version of Paragon \cite{Paragon}, 
with a very direct correspondence to the 
graph-rewriting framework in which Paragon has been presented.
Although the first application of OGRe has been in the implementation of \F, the model is general and can be used to model a number of other computational models rather directly. The characteristics of the model have been chosen carefully in order to allow a very simple implementation of OGRe on existing hardware.

In the next section we introduce the Object Graph Rewriting model of computation. A more formal sematics is presented in Section~\ref{sect:semantics}. Section~\ref{sect:examples} provides an outline of the way in which the model may be used to model a number of programming language styles. Section~\ref{sect:implementation} discusses existing language implementation via OGRe and potential for future exploitation of the model. It is argued that the design of OGRe makes it possible to generate an efficient pseudo-parallel implementation on sequential machines or to provide fine grain parallel processes for hardware architectures able to exploit very low level concurrency.

\section{OGRe: A Small Process Language}

The {\em Object Graph Rewriting\/} (OGRe) language models a computation by a set of named processes which exchange messages. Rewriting rules determine the way in which a process responds to the arrival of a message.

The state of a process is given by a term over the set of process names and a set of constructor (function) symbols with fixed arities. The symbols are used to model standard primitve data types and structured values.
Messages are also terms defined in the same way and are sent to a specific named process.

OGRe computation proceeds according to pattern-directed rewriting rules. When a process receives a message, the term describing the state of the process and the  term forming the message are matched against the left-hand sides of the OGRe rules. When a match is found, the message is absorbed, the state of the process is changed, and new process and messages may be generated.
Rules may also make use of primitive data functions, such as the arithmetic operations on numbers.

The following example shows one of a number of possible ways in which arithmetic expressions might be translated:

\begin{eqnarray*}
\Prule {p} {Sub(r)} {Pair(Int(x),Int(y))} {{\Pcall {r} {Int(x+y)}}} {Sub(r)} \\
\\
\Prule {p} {SumSq(r)} {Pair(x,y)}{\Ppar{\Pdef{q}{Mul(s)}}{\Pcall {q} {Pair(x,x)}}} {SumSq(r)}
p:SumSq(r)?Pair(x,y) -> r:SqY(y,r), m:Mul(r), m!Pair(x,x)
SqY(y,r)?Int(xx) -> f:Fin(xx,r), m:Mul, m!Pair(y,y)
Fin(xx,r)?Int(yy)  t:Sqrt(r), a:Add(t), a!Pair(Int(xx),Int(yy)) 
\end{eqnarray*}

\section{OGRe Examples}\label{sect:examples}

In this section we illustrate the power of OGRe by showing how a number of models of computation may be represented in a direct way.

\subsection{Modelling Dataflow}

In dataflow, an operator waits for a number of tokens to arrive, carrying data values. The operator then computes a result and sends it on to a further operator. We sketch a model of dataflow in OGRe where operation nodes become processes and data tokens become messages.
In line with the tagged dataflow model of the Manchester Dataflow Machine~\cite{MDFM}, we will label tokens as left or right arguments using symbols $L$ and $R$. When processes representing nodes are created, they will take an argument indicating the node to receive the result, and also which argument of the successor node will be formed by the result token.

\begin{eqnarray*}
\PruleChange {p} {Sub(d)} {L(x)} {SubR(r,x)} \\
\PruleChange {p} {Sub(d)} {R(y)} {SubL(r,y)} \\
\Prule {p} {SubR(R(d),x)} {R(y)} {{\Pcall {d} {R(x-y)}}}{Done} \\
\Prule {p} {SubR(L(d),x)} {R(y)} {{\Pcall {d} {L(x-y)}}}{Done} \\
\Prule {p} {SubL(R(d),y)} {L(x)} {{\Pcall {d} {R(x-y)}}}{Done} \\
\Prule {p} {SubL(L(d),y)} {L(x)} {{\Pcall {d} {L(x-y)}}}{Done}
\end{eqnarray*}

The first two rules take in the first argument and change the process state to await the second argument. The next two pairs of auxiliary rules await right, or left-hand arguments respectively. Two rules handle each of these cases since we must determine whether the resulting value is to become a left or right-hand input to the destination node.
Similar rules will exist for other operations.

Nodes which take a literal argument can be modelled by auxiliary nodes with suitable arguments as illustrated by the following fragment which would compute $3-(6*2)$ and send the result to a function $Print$. The result of the multiplication will become the right-hand argument of the subtraction node. The result of the subtraction becomes the left (only) argument of the print function.

\begin{eqnarray*}
& \Ppar{\Ppar{\Ppar{\Pdef{p}{Print}}{\Pdef{m}{SubR(L(p),3)}}}{\Ppar{\Pdef{a}{Mul(R(m))}}{\Pcall{a}{L(6)}}}}{\Pcall{a}{R(2)}}
\end{eqnarray*}

The sequence of execution might be as follows:
\begin{eqnarray*}
& & \Ppar{\Ppar{\Ppar{\Pdef{p}{Print}}{\Pdef{m}{SubR(L(p),15)}}}{\Ppar{\Pdef{a}{Mul(R(m))}}{\Pcall{a}{L(6)}}}}{\Pcall{a}{R(2)}} \\
& \rightarrow & \Ppar{\Ppar{\Ppar{\Pdef{p}{Print}}{\Pdef{m}{SubR(L(p),15)}}}{\Pdef{a}{MulR(R(m),6)}}}{\Pcall{a}{R(2)}} \\
& \rightarrow & \Ppar{\Ppar{\Ppar{\Pdef{p}{Print}}{\Pdef{m}{SubR(L(p),15)}}}{\Pcall{m}{R(12)}}}{\Pdef{a}{Done}} \\
& \rightarrow & \Ppar{\Ppar{\Ppar{\Pdef{p}{Print}}{\Pcall{p}{R(3)}}}{\Pdef{m}{Done}}}{\Pdef{a}{Done}}
\end{eqnarray*}

The reader can check that the result would be the same if the right-hand input to $a$ had been considered first. As tokens move through the graph the completed nodes are replaced by inactive $Done$ processes which can be garbage collected.

This example indicates the use of processes with state, and tagging of data value to identify a notional port in the receiving process. The example above contains no parallelism, but it is clear that in general there might be many token messages travelling between nodes, and hence many possible concurrent rewritings. The number of tokens will increase when a result is needed  by several successors, and a duplication node is used. Below, we give the rule for duplications and an example of how it could be used to form the square of a number:

\begin{eqnarray*}
\Prule {p} {Dup(L(d),L(e))} {L(x)} {\Ppar {\Pcall {d} {L(x)}} {\Pcall {e} {L(x)}}}{Done} \\
\Prule {p} {Dup(L(d),R(e))} {L(x)} {\Ppar {\Pcall {d} {L(x)}} {\Pcall {e} {R(x)}}}{Done} \\
\Prule {p} {Dup(R(d),L(e))} {L(x)} {\Ppar {\Pcall {d} {R(x)}} {\Pcall {e} {L(x)}}}{Done} \\
\Prule {p} {Dup(R(d),R(e))} {L(x)} {\Ppar {\Pcall {d} {R(x)}} {\Pcall {e} {R(x)}}}{Done}
\end{eqnarray*}
\begin{eqnarray*}
& \Ppar{\Ppar{\Ppar{\Pdef{p}{Print}}{\Pdef{m}{Mul(L(p))}}}{\Pdef{d}{Dup(L(m),R(m))}}}{\Pcall{d}{L(6)}}
\end{eqnarray*}

\subsection{Modelling Communication Channels}\label{sect:syncchannel}

The OGRe model is based on asynchronous direct communication between processes. There are no intervening channels as in CCS, or the \PPC. However, channel-based communication can be modeelled by OGRe processes. A channel is represented by a process which coordinates communication between producing and consuming processes. A producer sends a $Put$ message to the channel, with the data as arguemnt. A consumer sends a $Get$ message with the identity of the process to receive the data. Data is queued until a consumer is known. Unsatisfied requests are queued until a producer provides data.

The following model supports asynchronous communication since the producer receives no notfication that data has been consumed:

%\begin{figure*}
\begin{eqnarray*}
\Prule {c} {Chan(VQ(v,q))} {Get(r)} {\Pcall {r} {Data(v)}} {Chan(q)} \\
\PruleChange {c} {Chan(q)} {Get(r)} {Chan(RQ(r,q))} \\
\Prule {c} {Chan(RQ(r,q))} {Put(v)} {\Pcall {r} {Data(v)}} {Chan(q)} \\
\PruleChange {c} {Chan(q)} {Put(v)} {Chan(DQ(v,q))}
\end{eqnarray*}
%\caption{Rules for Asynchronous Communication}
%\label{fig:synccomm}
%\end{figure*}

Unsatisfied messages are stacked, so there is no fairness about this particular model. Surplus data values form a stack, $VQ$, of available values, while surplus producer names form a stack, $RQ$, of requests. Observe the order in which requests are satisfied in the following example execution:

\begin{eqnarray*}
& & \Ppar{c:Chan(EQ)}{\Ppar{c!Put(3)}{\Ppar{c!Put(4)}{\Ppar{c!Get(x)}{\Ppar{c!Get(y)}{c!Get(z)}}}}} \\
& \rightarrow & \Ppar{c:Chan(VQ(3,EQ))}{\Ppar{c!Put(4)}{\Ppar{c!Get(x)}{\Ppar{c!Get(y)}{c!Get(z)}}}} \\
& \rightarrow & \Ppar{c:Chan(VQ(4,VQ(3,EQ)))}{\Ppar{c!Get(x)}{\Ppar{c!Get(y)}{c!Get(z)}}} \\
& \rightarrow & \Ppar{c:Chan(VQ(3,EQ))}{\Ppar{c!Get(y)}{\Ppar{c!Get(z)}{x!Data(4)}}} \\
& \rightarrow & \Ppar{c:Chan(EQ)}{\Ppar{c!Get(z)}{\Ppar{x!Data(4)}{y!Data(3)}}} \\
& \rightarrow & \Ppar{c:Chan(RQ(z,EQ))}{\Ppar{x!Data(4)}{y!Data(3)}}
\end{eqnarray*}
The initial state of the channel holds and empty queue, $EQ$. The two $Put$ actions stack values so the $Get$ actions receive values in the reverse order.

It should be clear that the model for asynchronous channels could be modified to implement semaphores. No actual data values need be communicated, or stored.

Synchronous communication is possible if we arrange that a notification message, $Sync$, is sent to the producing process when the communication is completed. The producer must include the identity of the process to receive synchronisation when a data value is sent. Further computation by the producer can be blocked until the communication is completed: 

%\begin{figure*}
\begin{eqnarray*}
\Prule {c} {Chan(VQ(v,s,q))} {Get(r)} {\Ppar {\Pcall {r} {Data(v)}} {\Pcall {s}
{Sync}}} {Chan(q)} \\
\PruleChange {c} {Chan(q)} {Get(r)} {Chan(RQ(r,q))} \\
\Prule {c} {Chan(RQ(r,q))} {Put(v,s)} {\Ppar {\Pcall {r} {Data(v)}} {\Pcall {s}
{Sync}}} {Chan(q)} \\
\PruleChange {c} {Chan(q)} {Put(v,s)} {Chan(VQ(v,s,q))}
\end{eqnarray*}
%\caption{Rules for Synchronous Communication}
%\label{fig:synccomm}
%\end{figure*}

Note how an unsatisifed request blocks a thread of control as the channel process changes state but does not generate further actvity. When a communication completes, a new thread is activated as indicated by the two messages generated, one of which resumes the suspended thread of control.

\subsection{Modelling State and Logic Variables}

The channel model above uses a process to hold the state of the channel as a list of data values or requests. A simple von Neumann storage cell can be implemented with $Set$ and $Read$ operations. The $Set$ is acknowledged in order to provide serialisation. We return the old contents to allow a test-and-set functionality:
\begin{eqnarray*}
\Prule {c} {Cell(v)} {Set(n,r)} {\Pcall {r} {Data(v)}} {Cell(n)} \\
\PruleSpawn {c} {Cell(v)} {Read(r)} {\Pcall {r} {Data(v)}}
\end{eqnarray*}

By adding slightly more sophisticated behaviour, we can model a logic variable in the framework of concurrent logic programming~\cite{Shapiro}. The model suggested here is fior illustration only, as the properties of such variable vary from language to language. We will assume that an attempt may be made to $Bind$ an unbound variable, $UVar$. This will fail if the variable is already bound. A variable may be $Read$, which will lead to blocking of the computation if the variable is unbound. There is also an $IsVar$ test for examining the state of the variable. An unbound variable holds a list of suspended readers.
\begin{eqnarray*}
\PruleChange {c} {UVar(q)} {Read(r)} {UVar(Q(r,q))} \\
\PruleSpawn {c} {BVar(v)} {Read(r)} {\Pcall {r} {Data(v)}} \\
\Prule {c} {UVar(q)} {Bind(d,r)} {\Ppar{\Pcall {r} {Succ}}{\Ppar{\Pdef{f}{Free(q,d)}} {\Pcall{f}{Go}}}} {BVar(d)} \\
\PruleSpawn {c} {BVar(v)} {Bind(d,r)} {\Pcall {r} {Fail}} \\
\PruleSpawn {c} {UVar(q)} {IsVar(r)} {\Pcall {r} {Succ}} \\
\PruleSpawn {c} {BVar(v)} {IsVar(r)} {\Pcall {r} {Fail}} \\
\\
\Prule {f} {Free(Q(r,q),d)} {Go} {\Ppar{\Pcall{f}{Go}}{\Pcall {r} {Data(v)}}} {Free(q,d)} \\
\PruleChange {f} {Free(E,d)} {Go} {Done}
\end{eqnarray*}

The initial state of an unbound variable is $UVar(E)$. The rules for $Free$ are used to release suspended readers. In order to process the rest of the list, the process sends a further message to itself.

\subsection{Modelling Facile}

The OGRe model results in a very low-level translation of 
\F\ features in which potential implementation data-structures become 
visible. For example, \F\ channels can be 
represented as objects which are manipulated in exactly the same way 
as in the  \Cham\ \cite{CHAM} proposed for \F\ in \cite{FacileCHAM}. This channel representation is closely related to the synchronous channel model in Section~\ref{sect:syncchannel}.

For the purpose of investigation we present a very small language in 
which we can represent all the features of core \F, along with facilities for 
handling constants and operators as in ML.
This language is the \Lc\ with constants and pairing. The trivial
value and pairing operator could have been considered as normal constants.

\begin{eqnarray*}
e & ::= &  x \mid \Labs{x}{e} \mid \Lapp{e}{e} \mid c \mid () \mid \Lpair{e}{e} 
\end{eqnarray*}

$c$ stands for a constant and $x$ for a variable.

The features of \F\ are encoded in our source language as special constants in
very much the 
same way as in the sequential and
distributed implementations based on SML
\cite{KuoFacile,DistribFacile,MachFacile}.
The functionality is hidden in the definition of the constants $channel$,
$send$, $receive$, and $spawn$.

The function $channel$ takes a trivial value and returns a new channel
value. Every invocation of $channel$ returns a distinct channel value.

The function $send$ takes a pair containing a channel and a value to
be sent on the channel. A trivial value is returned when the output
action has succeeded. The function
has the effect of the SML/\F\ code $({\bf fn}\,(x,y)\,=>\,x!y)$

$receive$ takes a channel as argument and returns a value received as
the result of an input action. It has the
effect $({\bf fn}\,x\,=>\,x?)$.

The essence of \F\ behaviour
expressions, the scripts of processes, is provided by using delay closures,
functions of type $() \rightarrow ()$.
$spawn$ takes such a function and returns a trivial value having
created a process which runs in parallel. The spawned process executes
the behaviour expression by applying its
representation function to the trivial value,
terminating if the application terminates.
Although the original \F\ language provides more programming flexibility, it is
sufficient for our implementation experiments to concentrate on the four
primitives described above.

The following translation scheme maps the syntax to

\section{OGRe Semantics}\label{sect:semantics}



\section{OGRe Implementation}\label{sect:implementation}


\section{Conclusions}

\begin{thebibliography}{ECGS92}

\bibitem[{ABK92}]{Paragon}
P. Anderson, D. Bolton \& P. Kelly:
{\em Paragon Specifications: Structure, Analysis and Implementation}, \\
Proc PARLE'92. LNCS 605. June 1992. (1992) 

% *** More recent version in ?TCS?
\bibitem[{BeBo90}]{CHAM}
G. Berry \& G. Boudol:
{\em The  Chemical Abstract Machine},
Proc. POPL 90, p 81-94. (1990) 


\bibitem[{Gla92}]{Parle92}
J.R.W. Glauert:
{\em Asynchronous Mobile Processes
and Graph Rewriting}, 
Proc PARLE'92. LNCS 605. June 1992. (1992) 

\bibitem [{GLT91}]{SemSym}
J.R.W. Glauert, L. Leth \& B. Thomsen:
{\em A New Translation of Functions as Processes},
SemaGraph '91 Symposium, December 1991. (1991)

\bibitem[{GKW85}]{MDFM}
J.R. Gurd, C.C. Kirkham, \& I. Watson:
{\em The Manchester Prototype Dataflow Computer}, Comm. ACM, Vol. 28, No. 1, pp. 34-52, (1985).

\bibitem[{GPM89}]{Facile}
A. Giacalone, P. Mishra, \& S. Prasad:
{\em Facile: A Symmetric Integration of Concurrent and
Functional Programming},
IJPP, Vol 18, No 2, p121-160. (1989) 

\bibitem[{KC91}]{DistribFacile}
A. Kramer \& F. Cosquer:
{\em Distributing Facile},
MAGIC Note 12, ECRC. October 1991. (1991) 

\bibitem[{Kna91}]{MachFacile}
F. Knabe:
{\em A distributed protocol for the generalized select command},
MAGIC Note 11, ECRC. July 1991. (1991)

\bibitem[{Kuo92}]{KuoFacile}
Kuo, T.-M.:
{\em Magic Facile version 0.3},
MAGIC Note 22, ECRC. March 1992. (1992)

\bibitem[{Leth91}]{Leth91}
L. Leth:
{\em Functional Programs as Reconfigurable Networks of
Communicating Processes}, \\
Ph.D. Thesis, ICSTM. (1991) 

\bibitem[{LT92}]{FacileCHAM}
L. Leth \& B. Thomsen:
{\em Some Facile Chemistry},
ECRC Technical Report ECRC-92-14. May 1992. (1992) 

\bibitem[{Mil80}]{CCS}
R. Milner: 
{\em A Calculus of Communicating Systems},
Springer LNCS 92. (1980)

\bibitem[{Mil90}]{FunAsProcs}
R. Milner: 
{\em Functions as Processes},
Automata, Languages, and Programming. Springer LNCS 443. (1990)
Also: Technical Report INRIA Sophia Antipolis, June 1989. 

\bibitem[{Mil91}]{PolyPi}
R. Milner: 
{\em The \PPC: A Tutorial},
Technical Report ECS-LFCS-91-180, Edinburgh University, October 1991. (1991)

\bibitem[{MPW89}]{Pi}
R. Milner, J. Parrow, \& D. Walker: 
{\em A Calculus of Mobile Processes}, Parts I and II,
Technical Report ECS-LFCS-89-85, Edinburgh University, June 1989. (1989)

\bibitem[{Sha89}]{Shapiro}
E.Y. Shapiro:
{\em The Family of Concurrent Logic Programming Languages}, Computing Surveys, Vol. 21 (3), pp. 412-510. (1989)

% *** Correct Title required. MJ Wise?
\bibitem[{Wis92}]{MessageBrokers}
M. Wise: 
{\em Message Brokers and Communicating Prolog Processes}, 
Proc PARLE'92. LNCS 605. June 1992. (1992) 

\end{thebibliography}

\end{document}

\bibitem[{Abr88}]{Abr88}
S. Abramsky:
{\em The Lazy Lambda Calculus},     
Chapter 4 in D. Turner (ed.),
Research Topics in Functional Programming, 
pp. 65-116, Subison Wesley, 1988.

\bibitem[{Bur84}]{Bur84}
F.W. Burton: 
{\em Annotations to Control Parallelism and Reduction Order in
the Distributed Evaluation of Functional Programs},
TOPLAS, Vol 6, No 2, p159-174. (1984) 

\bibitem[{ECGS92}]{AM}
T. v Eicken, D.E. Culler, S.C. Goldstein \& K.E. Schauser,
{\em Active Messages: a Mechanism for Integrated Communication and
Computation},
International Symposium on Computer Architecture '92, ACM. (1992).

\bibitem [{GKS91}]{Dactl}
J.R.W. Glauert, J.R. Kennaway, \& M.R. Sleep:
{\em Dactl: An Experimental Graph Rewriting Language},\\
Proc. 4th International Workshop on Graph Gra\-mmars, Bremen, 1990.
Springer LNCS 532. (1991)

\end{document}
%%% End of LaTeX Document %%%
