DISTRIBUTED HASKELL: GOFFIN ON THE INTERNET 1 ... - CiteSeerX

0 downloads 0 Views 261KB Size Report
with combinators from concurrent constraint programming. ... previous publications, since it was adapted to Haskell 1.4.6) The typed, purely functional language ...
To appear in the Proceedings of the Third Fuji International Symposium on Functional and Logic Programming, World Scientic, 1998.

DISTRIBUTED HASKELL: GOFFIN ON THE INTERNET MANUEL M. T. CHAKRAVARTY Institute of Information Sciences and Engineering, University of Tsukuba Tennodai 1-1-1, 305 Tsukuba, Japan [email protected]

YIKE GUO and MARTIN KÖHLER Department of Computing, Imperial College 180 Queen's Gate, London SW7 2BZ, England

fyg [email protected] The constraint functional language Goffin extends the purely functional Haskell ;

with combinators from concurrent constraint programming. These combinators constitute a co-ordination sublanguage that allows to partition the overall program into parallel agents and to organize the communication them. The present paper extends Goffin's co-ordination portion with an operator for explicit agent placement as well as with temporal and port constraints. With these extension, special facilities of dedicated processing elements can be exploited, timeouts can be expressed, ecient n-to-m communication becomes possible, and dynamic interapplication communication is supported. We show that the resulting language is suciently expressive to cover interesting applications from the domain of distributed computing, and that, in particular, it can be used for Internet programming.

1 Introduction Goffin is a declarative parallel programming language, 1 2 which extends the ;

functional language Haskell with combinators from concurrent constraint programming. 4 These combinators constitute a co-ordination sublanguage that allows to partition the overall program into parallel agents and to organize the communication between these agents; in other words, it facilitates the specication of the co-ordination portion of parallel programs on a high level of abstraction. However, the computational portions are expressed in the functional base language Haskell. A central feature of Goffin is that it extends, but does not alter the semantics of Haskell; in particular, the extension retains referential transparency. Goffin's original purpose was the programming of massively parallel computers. Nevertheless, its basic design makes it also an interesting candidate for distributed computing. For this novel usage of the language, its co-ordination facilities have to be extended. The present paper discusses three new coordination mechanisms: explicit agent placement, temporal constraints, and port constraints. Agent placement is necessary as some applications require, in addition to partitioning the overall program into agents, also the explicit 1 3

assignment of some agents to xed processing elements. Such a requirement may, for example, arise from special capabilities of the hardware, such as a fast graphics display or an exceptionally high performance. Moreover, temporal constraints are necessary to express soft real-time constraints, such as timeouts. Finally, ports provide ecient n-to-m communication and support inter-application communication. Ecient n-to-m communication is crucial in many client-server applications and inter-application communication is needed when independent applications dynamically have to establish communication channels. The latter is central for applications like DNS (Domain Name Service) servers, Web servers and browsers, and other Internet applications. The contribution of the present paper is the extension of the application domain of Goffin from parallel to distributed programming, or more technically, the constraint-based co-ordination of purely functional computations as agents on local- and wide-area networks. In particular, the following technical contributions are made: The addition of explicit agent placement (Section 3). The extension of the constraint system with temporal constraints (Section 4.1). The use of internal ports for simple and ecient n-to-m communication. In particular, the original idea of port constraints, 5 as proposed for logic languages, is substantially revised, such that is better suited for the constraint-functional framework of Goffin (Section 4.2). The introduction of external port constraints for communication between independent applications, in particular, for Internet-based peer-to-peer and client-server applications (Section 4.2). To the best of our knowledge, this is the rst time constraints are used for inter-application communication. The focus of this paper is on language design, i.e., we neither dene the semantics of the new language features formally nor do we detail the implementation of these features. Instead, we informally discuss the merit of the extensions and provide programming examples. The paper is structured as follows: Section 2 reviews the fundamental concepts of Goffin. Section 3 discusses agent placement, and Section 4 covers temporal and port constraints. Thereafter, Section 5 applies the extensions in a a client-server and a peer-to-peer application. Finally, Section 6 discusses related work and summarizes. The appendix provides the grammar extension of Goffin for Haskell 1.4 and summarizes the additional prelude functions. 







2

2 Basic Gon

Before we discuss the extensions of Goffin that are needed for distributed computing, let us briey review the basic features of the language as introduced by Chakravarty et al. 1 2 (The syntax changed with respect to these previous publications, since it was adapted to Haskell 1.4. 6) The typed, purely functional language Haskell 3 forms the computational kernel of Goffin; and the following presentation assumes a basic familiarity with Haskell. Nevertheless, to get at least a basic impression of the language, consider the following denition of the Haskell version of the higher-order function map : ;

map map f [] map f (x : xs )

:: ( ! ) ! [ ] ! [ ] = [] = f x : map f xs

 type assertion  [] is the empty list  : is the inx list constr.

The function map maps a polymorphic function of type over a list (i.e., a list with elements of type ), yielding a list of type [ ]. Function application is by juxtaposition, [] denotes the empty list, and x : xs is a list with head x and tail xs . The reminder of this section discusses, rst, the specication of agents and the facilities to organize communication between them, and then, reviews the use of committed-choice indeterminism on the agent level. !

[ ]

2.1 Agents and Communication

In Goffin, purely functional expressions denote pure computation, whereas combinators originating from concurrent constraint programming 4 form an agent language, which is used to co-ordinate the concurrent execution of the functional computations. 7 1 We use the term agent for concurrently executing processes that communicate via monotonic renement of unbound (existentially quantied) variables by constraint imposition. In Goffin, agents are expressions of type O , which do not produce a result value, but merely succeed or fail;a furthermore, they ask and tell constraints to communicate. 4 The coordination layer of Goffin provides combinators for (a) the creation of agents that encapsulate computational tasks, (b) the composition of agents, and (c) the organisation of communication between agents. All three are discussed in the following. Given two agents a1 and a2 , we can compose them in parallel, as a1 N a2 , or sequentially, as a1 = a2 . Basic communication between agents is expressed ;

)

a

As usual in a committed-choice language, failure is terminal.

3

by equational constraints. The expression ex x in x :=: f a N g x introduces an unbound variable x , which is restricted to be equal to f a by the rst agent, and used as an argument to the agent abstraction g , which has type  O given that a is of type . The main dierence to the purely functional computation let x = f a in g x is that the agents x :=: f a and g x execute concurrently. The following is an agent-based, parallel version of map , which is called farm : !

farm farm f [] rs farm f (x : xs ) rs

:: ( ! ) ! [ ] ! [ ] ! O = rs :=: [] = ex rs 0 in rs :=: (f x ) : rs 0 N

farm f xs rs

0

Unlike map it does not yield a result value, but produces the resulting list by constraining the last argument rs appropriatelythis is a familiar technique in logic programming, and indeed, farm can be considered a predicative version of map . The rst equation of farm , used in case of an empty input list, simply constrains the result rs to the empty list. The second equation, used in case of a list cell x : xs , introduces a new unbound variable rs and constrains the result rs to be a list cell. The application of the mapped function f to the currently processed element of the input list forms the head of this result list and the new unbound variable rs represents the tail. This tail is computed recursively and in parallel (due to the use of N) to the application f x . Overall, an expression of the form farm foo l r uses the agent abstraction farm to apply foo to each element of the list l , such that all the applications may proceed in parallel. In other words, farm performs the same computation as map , but distributes the overall work over as many concurrent agents as the input list has elements. More details, examples, and a formal denition of the semantics can be found in Chakravarty et al. 1 0

0

2.2 Deferred Evaluation

A critical question concerning the integration of functional and concurrent constraint programming constructs is the interaction of unbound variables with function evaluation. If unbound variables are not handled with care, semantic properties of the functional base language will be lostfor example, the language Id 8 and its successor pH 9 break referential transparency.b b

In Id and pH, unbound variables are called I-structures.

4

In Goffin, the type system together with an evaluation strategy called

deferred evaluation,c ensures the integrity of the functional semanticsin par-

ticular, it preserves referential transparency. Deferred evaluation suspends any expression evaluation that depends on an unbound variable until the variable is bound (by some concurrent agent). As a result, the unbound state of a variable cannot be observed in the functional world. Let us assume the following denition of sum : sum sum [] sum (x : xs )

:: [Int ] ! Int = [] = x + sum xs

Consider, for example, the agent ex r :: Int ; l :: [Int ] in

farm foo [a ; b ] l N r :=: sum l

(Note that the type of the unbound variables may optionally be specied; here

r is of type Int and l of type [Int ].) It evaluates the application of foo to a and b as well as the summation of the results of these applications concurrently. Obviously, the application of sum immediately depends on the unbound variable l (in order to decided whether the rst or second equation of sum has

to be taken). Therefore, the strategy of deferred evaluation initially suspends sum l , but the application of farm may proceed. Unfolding the expression, we get ex r ; l ; xs1; xs2 in

l :=: (foo a : xs1 ) N xs1 :=: (foo b : xs2 ) N xs2 :=: [] N r :=: sum l

And after the constraint l :=: (foo a : xs1 ) takes eect, the second equation of sum can be deterministically chosen; but its recursive call initially suspends on xs1 , and so on. A formal denition of this semantics is given by Chakravarty. 2 The usefulness of partial data structures, i.e., data structures containing unbound variables, for parallel programming was illustrated elsewhere. 11 12 1 ;

2.3 Indeterminate Choice

;

It has been argued 13 14 1 that committed-choice indeterminism is useful for some applications from parallel computing; moreover, it is well-known that it is even more important in distributed computing. Therefore, Goffin provides ;

c

;

It is sometimes also called residuation. 10

5

merge merge xs ys zs choice

[] xs ; [] (x : xs 0 ) 0 f(y : ys )

f

f

:: [ ] ! [ ] ! [ ] ! O =

ys g xs g ys g

zs :=: [] ex zs in zs :=: (x : zs ) =) merge xs ys zs ! ex zs in zs :=: (y : zs ) =) merge xs ys zs

!

!

0

0

0

0

0

0

0 0

Figure 1: Indeterminate stream merging.

an indeterminate choice construct, which can be regarded as a disjunction over indeterminate ask expressions. 4 Its general form is the following: choice

fc11

c1m1 g ! e1 .. . fcn1 ; : : : ; cnm g ! en ;::: ;

n

ei is called an where the c are primitive constraints. Each ci1 ; : : : ; cim alternative, where the left-hand side of an alternative is called its guard and the right-hand side its body. The primitive constraints may have the form v1 v2 (alias constraint ) or p e (matching constraint ). An alias constraint is satised when the variables v1 and v2 are aliases, whereas a matching constraint requires that the value of e matches the pattern p. Variables contained in the pattern are bound during matching and may be used in the body expression of the alternative. The crucial point about the choice construct is that, whenever the constraints of one alternative are satised, the alternative can be taken and all other alternatives can be discarded. Note that due to the presence of unbound variables, a matching constraint may be neither satised nor refuted; instead, the decision is delayed until additional constraints, imposed by other agents, rene the data structure suciently, i.e., bind the corresponding variables. A classical example of the use of committed choice is indeterminate streammerging, which is, for example, used when multiple clients send requests to a single server. Its denition in Goffin is provided in Figure 1. The agent abstraction merge checks both input lists xs and ys for cons cells and adds any such cell to the result list zs . Note that the occurrence of unbound variables in the spine of any of the two lists may delay satisfaction or refutation of one alternative. In this case, the indeterminate nature of the construct guarantees that the agent consuming zs may proceed as soon as some list provides a list element, and thus, satises one of the choice alternative. This is in contrast to 6 j i



f

i

g !

a purely functional denition merging two lists, which statically has to commit to an order (like taking elements from the two lists alternatively), to preserve referential transparency. Details on the semantics of indeterminate choice in Goffin are provided by Chakravarty. 2

3 Agent Placement As discussed so far, Goffin allows to partition a complex task into paral-

lel subtasks by dening the complex task as a concerted action of a set of interacting agents. The distinction between co-ordination and computation allows granularity control, i.e., it allows the specication of those operations that may execute in parallel. However, the programmer sometimes also needs to control the location, i.e., processing element that executes a certain agent; such control is called explicit (agent) placement. Given an automatic load balancing mechanism, explicit placement is usually not necessary in parallel programsespecially, if they are meant for strongly-coupled multiprocessors. But the situation is quite dierent in distributed computing, where communication costs are usually signicantly higher; moreover, explicit agent placement is occasionally also useful in parallel programs. Generally, the following three situations require explicit placement: rst, an agent may need a resource, such as a special graphics terminal, which is available only on a certain processing node; second, sometimes explicit placement improves load balancing, especially in coarse-grained applications; and third, high-latency communication lines may require explicit programmer control over agent placement to avoid performance degradation. The central function for explicit placement in Goffin is hosts :: String ! O ! O

It requires the given agent to be executed on a specic processing element. It is usually used inx, as in fastMachine `hosts ` muchWork , where it requires muchWork to run on fastMachine . (In Haskell, alphanumeric inx operators are placed in back quotes.) The rst argument of hosts is a String that species the location where the agent, given by the second argument, should be executed. A location string consists of two parts separated by a colon, where the rst part species the network family and the second identies a member (processing element) of that family. There are two families that are always available: local and inet. The single member of the local family is "local :" (the member part is the empty string), which species the processor executing the hosts function. The inet family contains numeric and symbolic Internet addresses, for example, "inet : greyarea:is:tsukuba:ac:jp". Please note that it makes sense 7

to distinguish "local :" from "inet : localhost", as, for example, the nodes in a parallel computer often do not provide individual IP services; instead, the whole parallel machines is regarded as a single IP host. The basic set of locations can be extended by libraries, which may be machine dependent. For example, a library may provide an abstract view on some specic network topology or identify machines with special capabilities, i.e., machines connected to specic devices or having special performance characteristics. In a topology-based library, we would expect to have combinators that compute the neighbours of a given node and other topology-specic relations between nodes.

4 Enhanced Constraint System for Distributed Computing The co-ordination layer of Goffin basically adds support (1) for creation and

composition of potentially distributed, parallel agents and (2) for communication between these agents. The previous section introduced explicit placement as an additional feature for the rst point; the current section focuses on the second point and adds further communication facilities that are required in applications from distributed computing. In particular, we introduce temporal constraints to deal with timeouts and port constraints to provide ecient nto-m communication as well as communication between agents that are part of distinct applications (inter-application communication). Please note that the following does not provide a formal model for the extension of Goffin's constraint system, instead the new features are introduced from a practical language design and application point of view. 4.1 Temporal Constraints

The choice construct as introduced in Section 2.3 supports committed-choice alternatives that are guarded by alias and matching constraints, but applications from distributed computing sometimes require additional temporal constraints; for example, a client program may wish to choose a dierent server when a given server does not respond within a given time interval. To support such a behaviour, we propose temporal constraints of the form after t with t of type (Ratio Int ),d which are delayed (i.e., neither satised nor refuted) for t seconds after the constraint was initially checked, and after that time, are satised. The value of t must be positive (including zero); otherwise, a runtime error is raised. The use of fractions avoids xing some minimal time interval, which may become outdated as computer systems get faster. Using d

In Haskell, the type (Ratio Int ) contains fractions formed from two integer values.

8

the operator % from Haskell's Ratio library, we can write i %j to denote the fraction i divided by j . So, after (1 %100 ) is satised after 10 milliseconds. Returning to the example of a client that changes the server after some timeout interval let us assume, the answer of the server is a value of type data Result = Answer String

(Here, the new type Result is introduced, whose values are build using the data constructor Answer applied to a value of type String .) Then, the program fragment of the client that waits for the answer, may look as follows: ex ans ; : : : in

issue request

h

i

=) choice

process answer str use the second server After issuing the request, it leaves the rst server ten seconds to le the answer, by imposing a suitable constraint on the variable ans . If the matching constraint Answer str ans is not satised within that time interval, the temporal constraint after 10%1 is satised, which implies that the second server is used. Answer str

f

after 10%1g

f

f

ans g

! h

! h

i

i

g

f

g

4.2 Port Constraints The merge agent abstraction of Section 2.3 allows to implement an agent that

listens at two input streams simultaneously by merging them into one stream. Multiple of these mergers can be combined to provide n-to-m communication, for arbitrary n;e but unfortunately, such an implementation of n-to-m communication comes with some important drawbacks. 5 In particular, it can be rather inecient: In a naive implementation the number of operations needed to forward a message from a sender to a receiver is linear in n; a more ecient coding can improve this to a logarithmic dependence on n, but this can still result in signicant overhead. Another problem is that once such an nto-m merger process is created it is dicult to enlarge the number n of input streams, i.e., it is dicult to add new input streamsthe potential for dynamic increase of input streams has to be anticipated already during creation of the merging agent, which leads to an awkward programming style. Ports have been proposed by Janson et al. 5 to overcome the mentioned problems and, in particular, to provide constant time merging of an arbitrary number of senders and convenient dynamic extension of the number of input

e

Arbitrary m are trivial as the stream can be shared by many consumers.

9

streams. Such a port is a connection between (1) a handle that is used to send messages from multiple agents and (2) a stream collecting all these messages. The merging of the messages into a single stream is performed within the port, behind the scenes. Goffin's model of ports, although inspired by Janson et al., deviates signicantly from this previous proposal. There are three main dierences: (1) In Goffin, streams are used to input messages into a port, instead of posting single messages; (2) in Goffin, there can be multiple output streams that read from a port and that can be dynamically added; and (3) Goffin additionally provides a form of ports that support inter-application communication. The rst two points adapt the port model to the situation where the computational activities are written in a functional style (instead of a logic programming style as in the work of Janson et al. 5). The last point is important for the communication between dierent programs, whereas the original port model did only consider communication within one programwhich is to restrictive for Internet programming, where independently written applications have to communicate in an unpredictable, dynamic fashion (for example, like the DNS servers of dierent domains, which may be added and removed, while other servers still proceed).

Multiway Ports

We regard a port as an unidirectional, typed communication medium, which has type Port where is the data type that is communicated via the port (in particular, ports can be communicated via ports). We distinguish two kinds of ports: internal ports and external ports. An internal port is exclusively used within one application, whereas an external port is associated with a symbolic name that can be used by any application with network access to the processing element that hosts the port. In the following, we will rst discuss internal ports; external ports are described afterwards. A new internal port is created by the constraint port p , where p has to be of type Port . Given such a port p , there are two constraints that are used to communicate via a port; they basically attach output and input streams, respectively, to the port. () :: [ ] Port a O  pull messages out of a port () :: [ ] Port O  inject messages into a port A constraint of the form s  p makes s into a stream (a lazily created list) of the messages communicated via port p after the  constraint takes eect. In other words, an agent that imposes such a constraint becomes a reader of the 10 !

!

!

!

port, but it does not have access to old messages that have been communicated via the port before it became a reader. The reason for this choice of behaviour is that the port would have to retain all messages in case that some future reader likes to access them, which would cause a serious space leak in many applications. In contrast, ms  p injects a list of messages ms into the port p , i.e., it constrains p to contain the elements of ms . Note that this list may be created on demand from the port, and so, may constitute a stream of messages that ow into the port. The agent abstraction merge from Section 2.3 can be dened with ports as follows (the inx operator  binds stronger than = ): )

merge merge xs ys zs

:: [ ] ! [ ] ! [ ] ! O = ex p in port p =) zs

p=

)

(xs

 p N ys  p )

After the port p is created, zs is established as its single output stream, and both xs and ys as its input streams. The use of the sequential composition (= ) between the  and  constraints is essential to avoid the loss of any messages. It should be clear that the above denition can be generalized to any number of input and output streams. Furthermore, additional input and output streams can be added to the port by additional  and  constraints even after the port was used for some time; the latter is in sharp contrast to the merge abstraction of Section 2.3. )

External Ports

As argued above, particularly in Internet applications, communicationchannels have to be established dynamically between independent applications. In other words, an application has to be able to make some of its ports externally visible, such that they can be accessed by other applications on the same or other processing nodeswe call such ports external ports. This leads to two questions: (1) how does an application identify an external port of another application and (2) which kind of data can be communicated via such a port? We answer the rst question by identifying the externalization of a port with naming it, i.e., with assigning an alphanumeric identier to the port. A port that was named "renderer" on the machine LimitingFactor.cs.tu-berlin.de can be referenced as "renderer@inet : LimitingFactor:cs:tu-berlin:de" by other applications anywhere on the Internet. The machine name after the character `@' has the structure introduced for agent placement in Section 3. The simplest answer to the second of the above two questions is that we restrict inter-application communication to data types that have a textual representation, i.e., we require them to be in the Haskell type classes Show and 11

Read (which provide functions to convert a value into a string and vice versa).

This guarantees interoperability between arbitrary machine types, although it may have a negative inuence on performance. Nevertheless, we move the investigation of more sophisticated schemes to future work. Overall, we have the following two functions to externalization ports and to obtain external ports from other applications: named :: (Show a Read a ) ) Port a ! String ! O  assign global name access :: (Show a Read a ) ) String ! Port a ! O  obtain named port ;

;

Within a single application, the type system of Haskell ensures statically that messages put into a port are always of the type expected by any consumer. This guarantee can, of course, no longer be statically provided for external ports. Nevertheless, a dynamic check by the system is possible at the time of the use of the access constraint.

5 Two Example Applications We continue with a discussion of the basic structure of two example applications that employ the newly introduced features. 5.1 A Client-Server Example

To illustrate the use of agent placement in Goffin, we consider a simple client-server application. Assume that we like to display the result of a virtualreality animation on some intelligent graphics terminal. The animation is to be displayed concurrently with its computation on a parallel computer. After the simulation software started on the parallel machine, a rendering process has to be created on the graphics terminal. The choice where to create the renderer processes can, of course, not be left to the runtime system, but we have to enforce its creation on the graphics machine, using explicit placement. In our example, the communication between the animation software and the renderer is by a stream of graphics elements of type GElem , data GElem = Polygon [Point ] j   

The animation software produces the graphics elements and sends them to the renderer via a data stream of type [GElem ]. In Goffin, we represent the animation by an agent abstraction animate that gets a scenario as its rst argument and constrains its second argument to the stream of graphics elements. Furthermore, the renderer is an agent abstraction render , which 12

accepts a graphics stream: animate render

:: Scenario ! [GElem ] ! O :: [GElem ] ! O

Let us assume that the location of the graphics terminal is determined by a variable graphTerm , then the creation of the animation and rendering process as well as the placement of the latter on the graphics terminal is achieved by the agent abstraction simulation : graphTerm graphTerm simulation simulation sc

:: String = "inet : fancy:graphics:my:domain" :: Scenario ! O = ex gstream in

animate sc gstream N graphTerm `hosts ` (render gstream )

5.2 Dynamic Communication between Applications

As an example for communication between applications, consider a simple hierarchical name-server service. After startup a name server establishes an external port and listens for requests. Requests are rst looked up locally, and if this fails, the request is forwarded to a server that is higher up in the hierarchy. If that server does not respond within 60 seconds, the request is regarded as failed. Requests to the name server are represented by the following data type: data Request = Req

String (Port String ) deriving (Show ; Read )

In a request of the form (Req nameStr retPort ), the rst component, nameStr , is the name that should be looked up and the second component, retPort , is the port where the answer is expected. The deriving part of the data type denition makes the new type an instance of both the Show and the Read class, using a canonical string representation (cf. the Haskell language denition 6). Note that we regard ports of which the element type is in the Show and Read class as also belonging to Show and Read , respectively; overall, this allows us to send a port of type Port String over an external port. 13

answer answer [] answer (Req name client : rs ) where

:: [Request ] ! O

= success

= answer 0 (lookup name db ) N answer

rs

answer (Just res ) = [res ]  client answer Nothing = ex reply :: Port String ; resps :: [String ] in port reply =) resps  reply =) [Req name reply ]  master =) 0

0

choice

f[answer ] resps g ! [answer ]  client fafter 60%1g ! ["No response"]  client Figure 2: Main process of the name server agent.

The startup sequence of our name server, then, is as follows: ex socket :: Port Request ; reqs :: [Request ] in

port socket socket `named ` "nameserv" reqs  socket answer reqs

=) =) =)

 create port  externalize port  collect port messages in reqs  answer the requests

After nishing the startup sequence, the server processes the requests using the agent abstraction answer that is given in Figure 2. The agent processes the requests in parallel, i.e., when the response to one request is delayed, maybe because the server master is not responding, other requests are not stalled. If a local lookup succeeds, i.e., lookup name db evaluates to Just res , the result res is immediately returned via the port client . Otherwise, the name server forwards the request to another name server that is higher up in the hierarchy and can be reached via the port master . The response from that server is expected via a new external port fromMaster , and if it does not arrive within 60 seconds, the request is turned down. The latter is achieved using a temporal constraint in the choice expression. 14

6 Related Work and Conclusion Goffin is compared in detail to other functional and logic approaches to

parallel programming elsewhere. 1 With respect to distributed programming, the languages Distributed Oz, 15 Erlang, 16 and April 17 are probably closest. Oz and April have their roots in logic programming; Erlang while favouring a logiclike syntax is in eect an impure functional language. In contrast to Goffin, all three are untyped and they do not distinguish between co-ordination and computation. Recently, Marlow & Wadler 18 proposed a type system for Erlang, but it does not distinguish between computation and communication. So, none of these three languages is referentially transparent. Oz uses internal ports as introduced by Janson et al., 5 but has no external ports. Erlang uses a standard message passing scheme for communication. April supports inter-application communication, but assigns names on a per agent basis; communication is by message passing. Concurrent Haskell 19 is another extension of Haskell, which adds monadic concurrency combinators to Haskell. So far, the system is only used for concurrency on single-processor systems, i.e., there are no facilities for distribution. Furthermore, the Fudgets library 20 , originally intended to build GUI applications, provides limited support for inter-application communication in Haskell. The present paper discussed the introduction of explicit agent placement as well as temporal and port constraints into the constraint functional language Goffin. By means of two examples, we showed that the resulting language allows to elegantly code typical applications from distributed computing including inter-application communication, which is important for Internet programming. Apart from larger case studies, our future work will include formalizing the extended constraint system and investigating in which way external ports can communicate more sophisticated data structures and can avoid a purely textbased communication. In particular, it would be interesting to see whether the communication of functional values over external ports can be used as an abstraction for mobile code.

Acknowledgements

We like to thank Hendrik C. R. Lock for our fruitful collaboration in the initial denition of Goffin and the discussions that inspired the development presented in this paper. Martin Simons kindly pointed out some aws in a previous version of this paper. We also like to thank the anonymous referees for their helpful comments. 15

This work was partially supported by a Grant-in-Aid for Scientic Research on Priority Areas Research on the Principles for Constructing Software

with Evolutionary Mechanisms.

Appendix Goffin 1.4 is dened as an extension of Haskell 1.4. 6 Therefore, Goffin's

grammar is presented as an extension of Haskell's below. Please note that the font choice in this appendix diers from that in the main text, in order to closely match the description in Haskell language denition. In particular, terminals are set in typewriter font, whereas italic is used for nonterminals. exp10 ! ex vardecl1 , , vardecln in exp (unbound vars,  0) j choice { calts [;] } (indeterminate choice) :::

vardecl

n

! var [:: type ]

(variable declaration)

! calt1 ; ; caltn (  1) ! cgds -> exp [where decllist ] (choice alternative) ! { cgd1 , , cgdn } (choice guards,  1) ! pat :=: `hosts`

 type of agents

data O success (&), (==>) (:=:) hosts

:: :: :: ::

O O -> O -> O a -> a -> O String -> O -> O

 trivial constraint  parallel and sequential composition  equational constraint  placement operator for agents

Expressions of the form ex lvs in e, choice {calts}, are of type O, as are the bodies in ex and choice expressions. The interface for ports is dened as follows: module PreludePorts (Port, port, (), named, access) where infix 1 , `named`, `access`

16

data Port a  instance Text a => Text (Port a) port () named access

:: :: :: :: ::

Port a [a] -> [a] -> Text a Text a

-> O Port a -> Port a -> => Port a => String

polymorphic ports

 port instantiation

O  collect port messages in a stream O  post a message to a port -> String -> O  port gets global name -> Port a -> O  access gloabl port

References

1. Manuel M. T. Chakravarty, Yike Guo, Martin Köhler, and Hendrik C. R. Lock. Gon: Higher-order functions meet concurrent constraints. Science of Computer Programming, 30(12):157199, 1998. 2. Manuel M. T. Chakravarty. On the Massively Parallel Execution of Declarative Programs. PhD thesis, Technische Universität Berlin, Fachbereich Informatik, 1997. 3. P. Hudak et al. Haskell special issue. ACM SIGPLAN Notices, 27(5), May 1992. 4. Vijay A. Saraswat. Concurrent Constraint Programming. The MIT Press, 1993. 5. Sverker Janson, Johan Montelius, and Seif Haridi. Ports for objects in concurrent logic programs. In Agha, Wegner, and Yonezawa, editors, Research Directions in Concurrent Object-Oriented Programming. The MIT Press, 1993. 6. John Peterson et al. Haskell 1.4: a non-strict, purely functional language. Research report, Yale University, April 1997. 7. N. Carriero and D. Gelernter. Coordination languages and their signicance. Communications of the ACM, 35(2), February 1992. 8. R.S. Nikhil. Id (version 90.0) reference manual. Technical report, MIT Laboratory for Computer Science, July 1990. CSG Memo 284-1. 9. Rishiyur S. Nikhil, Arvind, James E. Hicks, Shail Aditya, Lennart Augustsson, Jan-Willem Maessen, and Y. Zhou. pH language reference manual, version 1.0. Technical Report CSG-Memo-369, Massachussets Institute of Technology, Laboratory for Computer Science, 1995. 10. H. Aït-Kaci, P. Lincoln, and R. Nasr. Le fun: Logic, equations, and Functions. In Proceedings of the 4th IEEE International Symposium on Logic Programming, 1987. 11. Arvind, R. Nikhil, and K. Pingali. I-structures: Data structures for parallel computing. ACM Transactions on Programming Languages, pages 598632, Oct 1989. 17

12. Ehud Shapiro. The family of concurrent logic programming languages. ACM Computing Surveys, 21(3):412510, 1989. 13. K. Mani Chandy and Stephen Taylor. An Introduction to Parallel Programming. Jones and Bartlett Publishers, 1992. 14. Silvia Breitinger, Rita Loogen, and Yolanda Ortega-Mallén. Towards a declarative language for parallel and concurrent programming. In David N. Turner, editor, Functional Programming, Glasgow 1995. University of Glasgow, Springer-Verlag, 1996. 15. Seif Haridi, Peter Van Roy, and Gert Smolka. An overview of the design of Distributed Oz. In M. M. T. Chakravarty, Y. Guo, and T. Ida, editors,

Multi-Paradigm Logic Programming (Proceedings of the JICSLP'96 PostConference Workshop), number 96-26 in Forschungsbericht, pages 1324.

Technische Universität Berlin, Fachbereich Informatik, 1996. 16. J. Armstrong, R. Virding, C. Wikström, and M. Williams. Concurrent Programming in Erlang. Prentice Hall, second edition, 1996. 17. Frank McCabe and Keith Clark. April: Agent process interaction language. In M. J. Wooldridge and N. R. Jennigs, editors, Intelligent Agents, number 890 in Lecture Notes in Articial Intelligence, pages 324340. Springer-Verlag, 1995. 18. Simon Marlow and Philip Wadler. A practical subtyping system for Erlang. In 2'nd ACM International Conference on Functional Programming. ACM Press, June 1997. 19. Simon L. Peyton Jones, Andrew Gordon, and Sigbjorn Finne. Concurrent Haskell. In Proceedings of the 23rd ACM Symposium on Principles of Programming Languages. ACM Press, 1996. 20. Thomas Hallgren and Magnus Carlsson. Programming with fudgets. In Advanced Functional Programming, number 925 in Lecture Notes in Computer Science. Springer Verlag, 1995.

18

Suggest Documents