Towards Applicative Relational Programming
H. Ibrahim and M.H. van Emden

arXiv:cs/0602099v1 [cs.PL] 28 Feb 2006

16 March 1992
Abstract
Functional programming comes in two flavours: one where “functions are first-class citizens” (we
call this applicative) and one which is based on equations (we call this declarative). In relational
programming clauses play the role of equations. Hence Prolog is declarative. The purpose of this paper
is to provide in relational programming a mathematical basis for the relational analog of applicative
functional programming. We use the cylindric semantics of first-order logic due to Tarski and provide a
new notation for the required cylinders that we call tables. We define the Table/Relation Algebra with
operators sufficient to translate Horn clauses into algebraic form. We establish basic mathematical
properties of these operators. We show how relations can be first-class citizens, and devise mechanisms
for modularity, for local scoping of predicates, and for exporting/importing relations between programs.

1

Applicative versus declarative definitions

Some functional programming systems are applicative; others declarative. Relational programming, on the
other hand, only exists in declarative form. In this section we explain how we use this terminology, and
argue that relational programming should also have both declarative and applicative forms.

1.1

In functional programming

There are two ways for defining functions in functional programming, one using λ-expressions and the
other using equations. Consider for example the higher-order function “twice”. It can be denoted by the
λ-expression “λf.λx.f (f x)”; we call this an applicative definition. This function can also be defined in a
declarative style, that is, by asserting as true certain equations, as follows:
twice F = g(F)
g(F) X = F (F X)
The characteristics of each style can be summarized in the first two columns of table 1. In the applicative
style, functions can be results of functions, can be bound to variables, and so on. Hence they are much
like other types of values. This is not the case in the declarative style. As a result, it is sometimes said
that in the applicative style, functions are “first-class citizens.” Furthermore, it can be shown that the two
styles have complementary strengths, namely local scoping and modularity in the applicative one, and a
natural expression of recursion and selection in the declarative one. Thus it is valuable for a programmer
to have both available and to be able to switch effortlessly between the two. In functional programming,
the theory of such a combination has been developed and practical applications have been reported [1, 7]

1.2

In relational programming

“Relational programming” is a natural counterpart for functional programming, with relations instead
of function as basic entities. Logic programming, the best developed form of relational programming, is
exclusively based on Horn clauses, which constitute a declarative paradigm. As the third column of table
1 suggests, a major problem in relational programming is the absence of an applicative language in which
1

2
Characteristics − P aradigms
implicit
element at a time
declarative
explicit
whole function/relation
applicative

f unctional

relational

equations

definite clauses

λ − calculus

?

Table 1: Classifying functional and relational definitions.
relations can be first-class citizens. This paper develops the basis for such a language, keeping in mind the
importance of it being first-order, and easily intertranslatable.

2

The meaning of Horn clauses

As basis for applicative relational programming, we use an algebraic view of the meaning of Horn clauses.
The following example serves as introduction. Consider the clause for relational composition: p(X, Z) ←
q(X, Y ), r(Y, Z). Relation p is defined by means of operations on q, r, and the tuples of variables. We make
these operations explicit by appealing to cylindric set algebra [4, 5]. Accordingly, a Horn clause can be
interpreted as a relational inclusion where the right-hand side is a projection of the intersection of cylinders
on the relations in the condition part. Consider, for example, the geometric interpretation of the clause as
illustrated in figure 1.
Figure 1: A geometric interpretation of relational composition: p contains the projection of the intersection
of the cylinders on q and r.
This can be expressed by a formula using the operators of T RA introduced in this paper. As a preview,
we list the formula here: p ⊃ (X, Z)/(q : (X, Y ) ∩ r : (Y, Z)), where “:” is relational application yielding a
cylinder, “∩” is intersection, and “/” is relational projection. To allows local scoping through λ-binding,
we want to have p, q, and r as relational variables. This also allows minimization operators, such as µ [3],
to apply as well. The result will be relation-valued expressions in a first-order setting.

2.1

Relational semantics for first-order logic.

Truth-functional semantics for first-order logic is an assignment of a truth value to a closed formula, where
this assignment is relative to a given interpretation that assigns meanings to constants, function symbols,
and predicate symbols. Relational semantics assigns a meaning to a formula that may have free variables;
i.e. an open formula. It gives as meaning the relation consisting of the tuples of individuals that, if
assigned to the free variables in the formula, would give a true closed formula according to truth-functional
semantics.
For example, the meaning with respect to an interpretation I of the formula q(X, Y ) under relational
semantics is the binary relation
r = {(α, β)|q(α, β) is variable-free and true in I}
For the benefit of further examples, suppose that the universe of discourse is {a, b, c}1 and that r =
{(a, b), (b, c), (c, a)}.
Note that the meaning of a relation under relational semantics is invariant under renaming of free
variables. As a result, relational semantics is not a homeomorphism between the algebra of formulas and
1 The

above footnote applies here also.

3
the algebra of relations. For example, if it were a homeomorphism, then the meaning of q(X, Y ) ∧ q(Y, Z)
would be the intersection of the meanings of the conjuncts. Hence it would be r ∩ r = r. However, it
should be the composition of r with itself according to the algebra of binary relations.
Therefore we need something else: cylindric semantics, introduced in the following.
Tarski’s cylinders. Tarski introduced a device that leads to a semantics for formulas that is a homeomorphism. Consider relations that are subsets of D1 × · · · × Dn (call this the domain product) and consider
a relation b (call it the base) that is a subset of Dj1 × · · · × Djk where the selector, J = {j1 , . . . , jk } is a
subset of {1, . . . , n}.
Then πJ−1 (b) = {(x1 , . . . , xn )|xi ∈ Di , i = 1, . . . , n and (xj1 , . . . , xjk ) ∈ b} is the cylinder with base b,
domain product D1 × · · · × Dn , and selector J. A cylinder, being a set of tuples of the same length, is
always a relation. But a relation is not always a cylinder.
For example, take a domain product with n equal to 3, D1 = D2 = D3 = {a, b, c}, with selector equal
to {1, 2}, and with base r = {(a, b), (b, c), (c, a)}. Then the cylinder specified by these properties is
{ (a, b, a), (a, b, b), (a, b, c),
(b, c, a), (b, c, b), (b, c, c),

(1)

(c, a, a), (c, a, b), (c, a, c) }
Rather than to assign to a formula as meaning a relation according to relational semantics, Tarski
assigns a cylinder on this relation. He assumes an enumeration of all variables in the language. This gives
a set J = {j1 , . . . , jk } of integers for a formula with k free variables. The semantics according to Tarski then
assigns to the formula as meaning the cylinder determined by J as selector on the base that is the relation
obtained by relational semantics. Such a semantics is a homeomorphism where conjunction corresponds
to intersection. Other syntactic constructs correspond to other operations in what Tarski calls “cylindric
set algebra.”
To return to our example, suppose X, Y , and Z are the only variables in the language (hence n = 3),
and are enumerated in this order. Then the free variables of q(X, Y ) correspond to the selector J = {1, 2}.
According to Tarski, the meaning of q(X, Y ) is then cylinder 1. The free variables of q(Y, Z) correspond
to the selector J = {2, 3}. According to cylindric semantics, the meaning of q(Y, Z) is then
{ (a, a, b), (b, a, b), (c, a, b),
(a, b, c), (b, b, c), (c, b, c),
(a, c, a), (b, c, a), (c, c, a) }

(2)

The meaning of q(X, Y )∧q(Y, Z) is the intersection of these two cylinders, that is, {(a, b, c), (b, c, a), (c, a, b)}.
According to Tarski, the meaning of ∃Y.q(X, Y ) ∧ q(Y, Z) is obtained by projecting this with selector
J = {1, 3}. The result is {(a, c), (b, a), (c, b)}, which is the relational composition of r with itself.
In this paper we define an algebra operating on cylinders and relations that allows us to translate to
algebraic form the definite clauses of Prolog. We call it TRA, for Table/Relation Algebra. The current
example serves to give a preview of this translation. Let a relational composition be defined by the clause
p(X, Z) ← q(X, Y ), q(Y, Z).
In classical syntax this is
(∃Y.q(X, Y ) ∧ q(Y, Z)) ⊃ p(X, Z).
As we just observed, the condition has as meaning the projection on (X,Z) of the intersection of the
cylinders denoted by q(X, Y ) and q(Y, Z). In general, we shall see that a definite clause asserts, interpreted
in terms of TRA, that the meaning of the conclusion includes the projection (determined by the variables
in the conclusion) of the intersection of the cylinders that are the meanings of the conditions.

4

2.2

Cylinders defined as tables.

It is rare to be able to list, as a set of tuples, a cylinder that is a meaning of a formula; the language usually
has infinitely many variables, so that the tuples are very long. Moreover, there are often infinitely many
tuples in the cylinder. But there is no problem specifying such a cylinder, as we only need to specify the
base relation and the selector (the domain product is usually implicitly understood).
For example, cylinder 1 can be specified by the set of substitutions
{{X = a, Y = b}, {X = b, Y = c}, {X = c, Y = a}},
as this specifies that the base relation of the cylinder is {(a, b), (b, c), (c, a)} and that the selector is {1, 2},
which corresponds to the variables X and Y in the enumeration.
Sets of substitutions of this type, where the substituted variables in each are the same, play a central role
in this paper. Observe, in the first place, that a table is a natural notation for such a set of substitutions.
The right-hand sides make up the lines of the table, while the left-hand sides need not be repeated, hence
can be the headings of the table’s columns; see table 2. Because of this, we call such sets of substitutions
“tables.”
X
a
b
c

Y
b
c
a

Table 2: A table for cylinder 1.
In the second place, observe that the set of answers to a Prolog query is a table. For example, suppose
that the logic program P is the set of facts {q(a, b), q(b, c), q(c, a)}. The query ?– q(X, Y ) produces table 2
as set of answer substitutions.

3

The Table/Relation Algebra (TRA)

TRA is an algebra of operations on relations, tables, queries, and logic programs. It facilitates translation
to and from definite clause form, and also facilitates scoping and modularity.
We define an n-ary relation over a Herbrand universe H to be a set of n-tuples of elements of H.
Prolog’s answer substitutions for the set of variables in a query can be regarded as a set of equations in
solved form; i.e. all left-hand sides are variables that occur only there [6]. Restricting the solved forms to
have a common set of variables as left-hand sides makes it natural to present a set of answer substitutions
as a table. Hence we define an n-ary table to be a set of sets of equations in solved form, where each set
of equations in the table has the same set of n variables as left-hand sides.
The reason for calling the concept just defined “table” is that these sets of equations can be most
economically represented in print as a table where the left-hand sides are the headings of the columns
(analogous to the attributes of relational data models) and the right-hand sides are the entries of the table.
A difference with the relational data model is that in our concept of table the entries can be terms of any
complexity containing variables without any restriction.

3.1

Tables as queries on logic programs.

Tables, as defined above, can be obtained, in logic programming, as follows:
Definition 1 Let P be a logic program, let Q be a query, and let T be an SLD-tree for P and Q. Then the
expression (Q where P ) has as value the table of the answer substitutions associated with all the success
leaves of T .

5
When in Prolog a query Q fails for a logic program P , there are no answer substitutions and the table
(Q where P ) is empty. We use the symbol ⊥ (bottom) for all of the empty tables {}. We use another
special symbol ⊤ (top) for the table consisting only of the empty answer substitution {{}}, which results
from a successful SLD-derivation starting in a query with no variables.
The following lemmas follow from the definition of “where”.
Lemma 1 θ ∈ (Q where P ) implies that θ is a correct answer substitution for {Q} ∪ P.
Lemma 2 For every correct answer substitution θ for {Q} ∪ P , ∃ η ∈ (Q where P ) such that θ is an
instance (with respect to the Herbrand universe) of η.
Lemma 3 The value of (Q where P ) does not depend on the SLD-tree T in definition 1.

3.2

Intersection of tables

Tables are a convenient notation for cylinders. As the intersection of cylinders is important, we need
to define intersection between tables. Let θ1 and θ2 be answer substitutions to the queries G1 and G2
respectively, and consider the query ?– G1 , G2 . When G1 and G2 have a common variable, θ1 ∪ θ2 is not
in solved form and may not be solvable. However, as Colmerauer [2] observed, the solved form of θ1 ∪ θ2 ,
if it exists, is an answer substitution for the query ?– G1 , G2 . Hence:
Definition 2 The intersection operation of tables S and T is
def

S ∩ T = {φ(s ∪ t) | s ∈ S, t ∈ T, and ψ(s ∪ t)}.
Here ψ(s) means that its argument set of equations is solvable; φ(s) is only defined when s is solvable
and then it denotes the solved form of s. For example, if relation q, as defined in a program P , is
{(a, b), (b, c), (c, d), (d, e)}, then the result of the query ((← q(X, Y )) where P ) ∩ ((← q(Y, Z)) where P ) is
table 3.
X
a
b
c

Y
b
c
d

Z
c
d
e

Table 3: A table from intersection of two tables.
The reason for choosing the name “intersection” and the symbol “∩” is given by the following
Theorem 1 For all tables S and T, S ∩ T is the set intersection of S and T regarded as cylinders (hence
relations, hence sets).
It is easy to verify the following properties about the intersection of tables:
Theorem 2 ∩ is associative and commutative. ∩ has a unique null element, which is ⊥ and a unique unit
element, which is ⊤.
Theorem 3 For any program P and goal statements G1 , G2 and G which consists of all goals in G1 and
G2 , we have
(G1 where P ) ∩ (G2 where P ) = (G where P ).

6
Modularity The previous theorem suggests using the combination of where and ∩ as a modular compositional tool, as in the following example:
((← F1 , F2 ) where P ) ∩ ((← G) where Q).
Thus we see that within the same table it can be specified of each goal with respect to which program it
is defined.

3.3

From relations to tables

We often need to get a table out of a relation, rather than from a program by posing a query. For this we
define the relational application operator “:”. We introduce its definition through a heuristic development.
Let r be the n-ary relation {(a1 , . . . , an ), (b1 , . . . , bn ), (c1 , . . . , cn )}. A table “most like” r can be easily
constructed by adding as a heading a set of n distinct variables, say X1 , . . . , Xn , as in table 4. This table
X1
a1
b1
c1

···
···
···
···

Xn
an
bn
cn

Table 4: A table “most like” r.
can then be identified using an arbitrary predicate symbol, say p, as follows:
(← p(X1 , . . . , Xn )) where {p(e1 , . . . , en ) | (e1 , . . . , en ) ∈ r}.
The obvious generalization of allowing any terms t1 , . . . , tn instead of the distinct variables suggests
def

r : (t1 , . . . , tn ) = (← p(t1 , . . . , tn )) where {p(e1 , . . . , en ) | (e1 , . . . , en ) ∈ r}.
Though correct, its arbitrary and auxiliary predicate p is undesirable. It is easily verifiable that this
definition is equivalent, operationally, to:
Definition 3 The application operation of an n-ary relation r to a tuple (t1 , . . . , tn ) of terms is
def
r : (t1 , . . . , tn ) =
{φ({t1 = e1 , . . . , tn = en }) | (e1 , . . . , en ) ∈ r and ψ({t1 = e1 , . . . , tn = en })}.

3.4

From tables to relations

Just as we defined the application operator to get tables from relations, we define a projection operation
to get relations back from tables. This operation should not merely discard the table’s “headings”2, as
suggested in [9]. Instead, we present another heuristic development to define it properly.
Let T be the previous table 4. Now, {(X1 θ, . . . , Xn θ) | θ ∈ T } is the relation resulting from discarding the heading; i.e. r above. To generalize, we first let {j1 , . . . , jk } be a subset of {1, . . . , n}. Then,
{(Xj1 θ, . . . , Xjk θ) | θ ∈ T } is a projection of r over the (j1 , . . . , jk ) columns. Hence, projection is a way
of getting a relation from a table. Secondly, allow any tuple (t1 , . . . , tk ) of terms instead of the variables
(Xj1 , . . . , Xjk ) and consider {(t1 θ, . . . , tk θ) | θ ∈ T }. Since for an arbitrary table T any θ ∈ T may contain
variables, the result must further be grounded in order to obtain a relation. Hence the final definition:
Definition 4 The projection operation (denoted /) of a table T over a tuple of terms (t1 , . . . , tn ) is
def

(t1 , . . . , tn )/T = ξ({(t1 θ, . . . , tn θ) | θ ∈ T }),
where ξ(x) is the set of variable-free instances of the expression x.
2 One reason is, as mentioned before, that our table’s contents include variables, whereas the elements of a relation’s tuples
are variable-free.

7

3.5

Are project and apply inverses?

Now that we have operations from tables to relations and vice versa, one may wonder whether these are
each other’s inverses. The short answer is, in general, “no”, because
((t1 , . . . , tn )/T ) : (t1 , . . . , tn )
is not always the table T . Take, for example, the case that t1 , . . . , tn have no variables. Then the above
expression is ⊤ whenever T is not ⊥. But the absence of variables in t1 , . . . , tn is a rather pathological case.
When we add restrictions, we can say that, in a sense, “/” and “:” are each other’s inverses, as shown by
the following theorems.
Theorem 4 For all tables T and all terms t1 , . . . , tn in which all the variables, and no other ones, in T ’s
heading occur, we have
((t1 , . . . , tn )/T ) : (t1 , . . . , tn ) = ξ(T ).
For an inverse in the other direction, compare the n-ary relation r with
(t1 , . . . , tn )/(r : (t1 , . . . , tn )).
That this expression does not always equal r is shown by (c, d)/({(a, b)} : (c, d)) = {}, where a, b, c and d
are constants. This example suggests:
Theorem 5 For all n-ary relations r and all terms t1 , . . . , tn , we have
(t1 , . . . , tn )/(r : (t1 , . . . , tn )) ⊆ r.
However, by strengthening the restrictions, we can have equality instead of inclusion.
Theorem 6 For all n-ary relations r and all distinct variables x1 , . . . , xn , we have
(x1 , . . . , xn )/(r : (x1 , . . . , xn )) = r.

3.6

Translation of definite clauses to TRA

It should be clear now that the operators of TRA correspond closely to the operations hidden in definite
Horn clauses, according to cylindric semantics. This simplifies the translation of definite clauses to TRA,
and we therefore omit an explicit description of it.
The principle of the translation is that each definite clause states that the relation denoted by the
predicate symbol in the conclusion includes the projection (on the tuple of the terms in the conclusion) of
the intersection of the tables denoted by the conditions. The operations of TRA are general enough to
translate the definite clauses of pure Prolog.
Example. We illustrate the translation by an example that is a typical Prolog program. It gives a
quicksort program from an ordinary list to a difference list.
The Prolog program is:
qsort([ ],U-U).
qsort([X|Xs],U-W) :partition(X,Xs,Y1,Y2),qsort(Y1,U-[X|V]),qsort(Y2,V-W).
The TRA version is:
qsort ⊇ (([ ], U − U )/⊤)
∪ (([X|Xs], U − W ) /

(((← partition(X, Xs, Y 1, Y 2)) where P )
∩(qsort : (Y 1, U − [X|V ]))
∩(qsort : (Y 2, V − W )))).

8
qsort is a relational variable and is not part of the language of clausal logic. But all terms, and the
atomic formula that is the first argument of where, are in clausal logic.
The entire expression states an inclusion between relations and may or may not be satisfied, depending
on the value of qsort. It may be shown that there is a least relation as value for qsort that satisfies the
inclusion. The inclusion serves as definition of this least relation.
The applicative relational program has the following advantages:
1. The where expression has a table as value and can be replaced by any other expression with the
same value; see item 3. In particular, the identifier partition is local to the where expression. The
declarative Horn clause formalism does not provide locality for predicate names.
2. The identifier qsort is a variable and is not a predicate symbol. Hence a minimization operator, like
µ of [3], can be applied to the entire inclusion with respect to qsort. The result is a relation-valued
expression that can, for example, be the operator argument of the relational application “:”. The
identifier qsort is then local to this operator. In this way any number of levels of locality can be built,
just as in applicative functional programming.
3. Combining a selection/minimization operator with the functional λ-abstraction and application operators yields an import/export facility for relations between program modules. As an example, replace
P above with
(λorder.P )(νleq.Orderings),
where order is a relational variable in P used to define the order of partitioning, Orderings is a
program that defines different orders, and “ν” is the minimization operator that selects one of the
relations (leq) defined in a program module (Orderings). The effect of all this is exporting the leq
relation from program Orderings, and importing it into program P as the order of partitioning,
yielding an ascending, or descending, qsort relation.

4

Related work

This paper is a continuation of a line of research going back as far as the work of Peirce and of Schroeder in
the 19th century on algebra of relations. These algebras were not adequate to serve as basis for a semantics
for full first-order predicate logic. In the 1930’s Tarski provided cylindric set algebra, which remedied this
shortcoming. The simplicity of definite clauses, although covered by Tarski’s work, suggest the independent
treatment given in this paper.
After Tarski’s work, the next most important step was the paper by de Bakker and de Roever [3]. By
restricting themselves to binary relations, they took their starting point before Tarski. They elucidated the
mechanisms of defining binary relations, especially the use of the minimization operator. TRA facilitates
extending of the definition techniques of de Bakker and de Roever to include the type of algebra introduced
by Tarski.
There are some relations to recent work that do not seem to be part of a grand design. Codd’s relational
calculus is declarative in spirit, whereas his relational algebra is applicative in spirit. Both seem to us to
be improved upon by the earlier work by Tarski. However, TRA can be viewed as a relational algebra
counterpart for the Datalog query language, when substituted for Codd’s relational calculus. Our where
expressions were inspired by Nait-Abdallah’s ions. The main difference is that Nait-Abdallah’s work is
syntactic, concentrating on rewriting rules.
Our work is also related to higher-order logic programming by having the same objectives, but a
different approach; see the concluding remarks. Finally, applicative programming constitutes important
related work [8], as mentioned in the introduction.

5

Conclusions

We have characterized distinctions between the applicative and declarative paradigms in functional programming. We have noted that relational programming exists only in declarative form. We have developed

9
a relational algebra (TRA) useful as a mathematical basis for applicative relational programming. The
operations of TRA are chosen in such a way that the definite clauses of Prolog have a simple translation.
Relations can be first-class citizens. One of the most powerful paradigms in computing is “functions
as first-class citizens” [8]. This in reaction to languages where functions are more restricted in their use
than, say, numbers. Certain functional programming languages have demonstrated the advantages of
having functions as first-class citizens. Prolog, the only relational programming language, does not have
relation-valued expressions of any kind. We have shown that relations can be first-class citizens.
Modular logic programming. We have shown how to support modularity and local scoping for relations, which is a deficiency in declarative logic programming. We have devised a mechanism that facilitates
the exportation and importation of relations between programs.
Higher-order logic is not needed, at least not to provide the desirable programming features implied
by having functions and relations as first-class citizens. In functional programming, a function is said to be
higher-order when it takes a function as argument or produces one as result. A logic is said to be higherorder when one can quantify over function or predicate symbols. These two senses of “higher-order” do
not coincide. This is proved by the existence of formalizations of λ-calculus in first-order logic. A constant
of logic can denote any individual, including a function. Therefore, a first-order variable, one ranging
over individuals, can range over functions. In that sense, our expressions contain first-order variables that
range over relations. This is an important point, as first-order logic is more tractable, theoretically and
practically, than higher-order logic.

6

Acknowledgments

Thanks to J.H.M. Lee for his careful reading of an earlier version of this work. Generous support was
provided by the British Columbia Advanced Systems Institute, the Institute of Robotics and Intelligent
Systems, the Canadian Institute for Advanced Research, the Laboratory for Automation, Communication
and Information Systems Research, and the Natural Science and Engineering Research Council of Canada.

References
[1] M.H.M. Cheng. Lambda-equational Logic Programming. PhD thesis, University of Waterloo, 1987.
[2] Alain Colmerauer. Prolog and infinite trees. In Logic Programming, pages 231–251. Academic Press,
1982.
[3] J.W. de Bakker and W.P. de Roever. A calculus for recursive program schemes. In M. Nivat, editor,
Automata, Languages, and Programming, 1973.
[4] L. Henkin, J. D. Monk, A. Tarski, H. Andréka, and I. Németi. Cylindric Set Algebras, volume 883 of
Springer Lecture Notes in Mathematics. Springer-Verlag, 1981.
[5] Leon Henkin, J. Donald Monk, and Alfred Tarski. Cylindric Algebras, Parts I,II. Studies in Logic and
the Foundations of Mathematics. North-Holland, 1985.
[6] Alberto Martelli and Ugo Montanari. An efficient unification algorithm. ACM Transactions of Programming Languages and Systems, 4:258–282, 1982.
[7] B.E. Richards. Contributions to functional programming in logic. Master’s thesis, University of Victoria,
1990.

10
[8] Joseph E. Stoy. Denotational Semantics: The Scott-Strachey approach to Programming Language Theory. MIT Press, 1977.
[9] Jeffrey D. Ullman. Principles of Database and Knowledge-Base Systems. Computer Science Press,
1988.

