Successful Logic Programs 1 Introduction 2 Basic ... - Semantic Scholar

1 downloads 0 Views 294KB Size Report
C1;:::;Cr: is the input clause used in the derivation step, = mgu(K; B1) and c is standardized apart wrt Q. First we prove that Q0 is output-free. 4 ...
Successful Logic Programs Annalisa Bossi, Nicoletta Cocco

Dip. di Matematica Applicata e Informatica Universita di Venezia-Ca' Foscari - Italy bossi, [email protected]

Abstract

We formalize the intuitive reasoning which we normally use to get convinced that a query has successful LD-derivations in a program. We give two sucient conditions: one for characterizing absence of nitely failing LD-derivations (FDs) and a weaker one for guaranteeing the presence of at least one successful LD-derivation if there are nite ones. These conditions can be useful both in verifying properties of logic programs and in program transformation. Keywords and Phrases: nitely failing derivations, program transformation, program veri cation

1 Introduction Logic programming is a declarative paradigm. This pleasant characteristic allows one to ignore the computation and simply de ne which are the desired results. But, when queried through a Prolog interpreter, logic de nitions are performed with backtracking: some fail and some succeed. Finitely failing LD-derivations (FDs) are not relevant from the logical point of view, unless the entire LD-tree is nitely failing. Thus FDs are ignored in the formal description of the program which is concerned only with successes and computed answer substitutions (c.a.s.) or with the total absence of successes for a given query. Also formal techniques for verifying program properties focus only on successful computations. Nevertheless FDs are relevant from the eciency point of view; in correctness veri cation absence of successes can be hidden; in Prolog program transformations, where the size of the LD-tree for a query is relevant, the presence of FDs can make dicult to check applicability conditions for transformation operations, such as unfold, replacements or switching of two atoms. On the other hand when we write a logic program, we have some intuitive con dence that it will produce the desired computed answer substitutions for some sets of queries. In some intuitive way we are able to distinguish failing computations from successful ones. We try to formalize this intuitive feeling, by giving a sucient condition which ensures that a given program and query are without failures, namely they cannot have nitely failing derivations (noFD). Then we discuss the use of this condition both in verifying program correctness and in program transformation. Our condition is very restrictive, since we want it to be veri able from the text of the program and failures are dicult to be syntactically characterized. Nevertheless we believe that it can be useful, since in general it is necessary to verify the condition only on some parts of the program. Besides we give a weaker sucient condition which ensures that a universally terminating query has at least one successful derivation in a given program. This corresponds to a larger class of programs, which we call successful programs, and can contain also test predicates. In Section 2 we set some notation, then in Section 3 the class of noFD programs and queries is introduced and exempli ed. We prove that a noFD query in a noFD program cannot nitely fail. In Section 4 we discuss how to use these concepts for verifying program correctness and for program transformation. In Section 5 the larger class of successful programs is de ned. We prove that a noFD query in a successful program has at least one successful LD-derivation. Conclusions follow in Section 6.

2 Basic Notions Given a substitution  and a set of variables X , we denote by jX the substitution obtained from  by restricting its domain to X . Given an expression (term, atom, query,. . . ) E , we denote the set of 1

variables occurring in it by Var (E ). We often write jE to denote jVar (E) . A renaming is a substitution which is a permutation of its domain. We write E  E 0 to denote that E and E 0 are variant expressions, that is there exists a renaming  such that E = E 0 . When a renaming of E maps V ar(E ) in \new" variables we call it a new renaming of E and we speak of E as a new variant of E . We consider de nite logic programs executed by means of the LD-resolution, which consists of the usual SLD-resolution combined with the leftmost selection rule as Prolog interpreters do. Throughout the paper we use queries instead of goals. A query is a sequence of atoms or fail. fail stands for the query associated to a failure and 2 for the empty query. An LD-derivation ending with 2 is a successful LDderivation, one ending with fail is a failing one (FD). We denote sequences by bold characters and we use identi ers to label clauses and derivations. Then l : Q j?!P R stands for "an LD-derivation, l, of the query Q in P , which ends in the query R and  is the composition of the relevant and idempotent mgu0s applied during the derivation". Similarly   Q j?!P 2 denotes a successful LD-derivation of Q in P with c.a.s. jQ. Q j?!P R denotes one derivation step, we say that it is non-trivial if R is not fail. The length of an LD-derivation l is denoted by j l j. The rest of the notation is more or less standard and essentially follows [21, 1]. In the paper we make use of the notion of modes and types introduced in [15, 4, 2]. We consider a combination of modes and types and adopt the following assumption: every considered relation has a xed mode and a xed type associated with it. This assumption allows us to talk about types of input positions and of output positions of an atom. For example, app(+ : List; + : List; ? : List) denotes a ternary relation app with the rst two positions moded as input and typed as List and the third position moded as output and typed as List. A similar denotation is called a directional type in [14]. From [4, 2] we take also the notion of well-typed query and program. A complete treatment of this topic can be found in [4, 2], here we recall only the main de nition. To simplify the notation, when writing an atom as p(u : S; v : T), we assume that u : S is a sequence of typed terms lling in the input positions of p and v : T is a sequence of typed terms lling in the output positions of p.

De nition 2.1 [Well-typed query, clause, program [2]]  A query p (i1 : I1 ; o1 : O1); : : :; pn (in : In ; on : On) is well-typed i for j 2 [1; n] j= o1 : O1 ; : : :; oj?1 : Oj?1 ) ij : Ij :  A clause p (o0 : O0 ; in 1 : In 1) p (i1 : I1 ; o1 : O1); : : :; pn (in : In ; on : On ): is well-typed i for j 2 [1; n + 1] j= o0 : O0 ; : : :; oj?1 : Oj?1 ) ij : Ij :  A program is well-typed i every clause of it is. 2 1

0

+

+

1

Thus, a query is well-typed if  the types of the terms lling in the input positions of an atom can be deduced from the types of the terms lling in the output positions of the previous atoms. And a clause is well-typed if  (j 2 [1; n]) the types of the terms lling the input positions of a body atom can be deduced from the types of the terms lling in the input positions of the head and the output positions of the previous body atoms,  (j = n + 1) the types of the terms lling in the output positions of the head can be deduced from the types of the terms lling in the input positions of the head and the types of the terms lling in the output positions of the body atoms. Note that a query with only one atom is well-typed i this atom is correctly typed in its input positions. 2

De nition 2.2 [Terms of B] Let P be a well-typed program and B a well-typed query in P . The terms of B are denoted by Term(B). The input (output) terms of B, denoted by In(B)(Out(B)), are the terms in input (output) positions in B. 2

3 Programs and Queries without Failures (noFD) In this section we give a sucient condition for absence of failing derivations. We assume to have moding and typing information and to deal only with well-typed programs and queries. Intuitively in an LDderivation, FDs may happen when some term is instantiated in an "incorrect" way, namely it forbids uni cation with further input clauses. This intuitively means that for avoiding FDs, inputs must be correctly given, while outputs should be correctly instantiated by the evaluation. We de ne an interesting class of programs: programs without failures (noFD programs). These programs have a clear functionality from input to output and they can be non-deterministic. They satisfy the strong property that, in an LD-Derivation, for any selected atom correctly typed in input positions and with uninstantiated variables in output positions, there exists a unifying clause in P . De nition 3.1 [output-free sequence] A well-typed sequence of atoms Q = B1; : : :; Bm is output-free i output positions are lled in with distinct variables which do not appear leftmost, namely 8j 2 [1; m], Out(Bj ) = V ar(Out(Bj )), if X1 ; : : :; Xk are the output terms in Bj , then Xi 6= Xh , for i 6= h, i; h 2 [1; k], and Out(Bj ) \ (V ar(B1 ; : : :; Bj?1 ) [ V ar(In(Bj ))) = ;.

De nition 3.2 [input-correct and output-free instance] Let A be an output-free atom and a substitution. We say that A is an input-correct and output-free instance of A i A is correctly typed in input and Out(A ) is a new variant of Out(A).

De nition 3.3 [noFD program] Let P be a well-typed program.

A clause c : H A1 ; : : :; An : in P is without failures (noFD clause) i 1. the sequence of atoms in the body A1 ; : : :; An is output-free; 2. V ar(In(H )) \ V ar(Out(A1 ; : : :; An )) = ;; 3. for all i 2 [1; n] and for any input-correct and output-free instance Ai of Ai , there exists a clause in P whose head uni es with Ai . A predicate p in P is without failures (noFD predicate) i all the clauses in (the deductive closure of) its de nition in P are noFD ones. The program de ning p is then a program without failures (noFD program). 2

De nition 3.4 [noFD query] Let Q = B ; : : :; Bm be a well-typed query. Q is without failures (noFD query) in a program P i 1. the sequence Q is output-free; 2. for j 2 [1; m] and for any input-correct and output-free instance Bj of Bj , there exists a clause in 1

2

P whose head uni es with Bj .

The condition for being noFD is local, namely each clause can be considered separately. Only atoms in the clause bodies and in the queries have to satisfy the restrictions, on the head atoms no restriction is required. Hence a well-typed program containing only facts is trivially noFD. Note also that the rst conditions are syntactic ones and then very simple to verify. The last condition is more complex since it is \semantic" and relates the clause to its context, but, if a type de nition is available, it can be statically veri ed as shown in the following simple examples.

Example 3.5 1) Let us consider the append program 3

app([ ], Ys, Ys). app([X Xs], Ys, [X Zs])

j

j

app(Xs, Ys, Zs).

with the directional type app(+ : List; + : List; ? : List). This program is noFD. In order to verify this, we observe that it is well-typed wrt its typing. The rst clause is a fact. Then we consider only the second clause. The clause has only one atom in the body: A1 = app(Xs; Y s; Zs), where Out(A1 ) = fZsg, which is a variable and Out(A1 ) \ V ar(In(A1 )) = fZsg \ fXs; Y sg = ;, Out(A1 ) \ V ar(In(H )) = fZsg \ fX; Xs; Y sg = ;. The rst two conditions of De nition 3.3 are then satis ed. Moreover for any input-correct and output-free instance of A1 , that is for any substitution such that Xs ; Y s 2 List and Zs is a new variant of Zs, we have a unifying clause in the program. In fact Y s uni es with a variable in both the clauses. By de nition of List, Xs is either an empty list or a non-empty one, the two cases are respectively captured by the rst and the second clause in the program. 2) Let us consider now the query Q = app([1]; [2]; Zs); app(Zs; [3]; Y s). It is a noFD query in the previous program app. In fact it is well-typed and output-free. Namely Out(B1 ) = fZsg, Out(B2 ) = fY sg and Out(B2 ) \ (V ar(B1 ) [ V ar(In(B2 ))) = ;. It also satis es the second condition in De nition 3.4. For B1 , with a new renaming of Zs, the second clause of append uni es. For B2 , with Zs 2 List and Y s new variant of Y s, one of the two clauses of append uni es since Zs is either an empty or a non-empty list. 3) Let us consider now the two queries: app([1]; [2]; a) and app([1]; [2]; [3]). They both are well-typed but they are not output-free. In fact Out(B1 ) is not a variable in both of them. 4) Let us consider the two queries Q1 = app([1]; [2]; Zs); app(Zs; [3]; Zs) and Q2 = app([1]; [2]; Zs); app([2]; [3]; Zs). These queries are well-typed but they are not output-free either. In this case the problem is that Out(B2 ) \ (V ar(B1 ) [ V ar(In(B2 ))) 6= ;. 5) Let us consider now append with the reverse directional type app(? : List; ? : List; + : List). Also in this case the program is noFD. The veri cation is trivial. Let us consider the query app(X; X; [1; 2; 3]) wrt the same directional type. This query is not noFD since it is not output-free, in fact Out(B1 ) does not contain distinct variables. 2 noFD programs and queries form a rather restricted class since output terms in the query and body atoms must always be uninstantiated variables. But this is also a very interesting class since we can prove that a noFD query in a noFD program cannot have FDs. First we state an important property of noFD programs and queries, namely that LD-resolution preserves the property of being noFD. Lemma 3.6 Let Q be output-free and  be a substitution such that V ar() \ V ar(Q)  (V ar(In(Q)) ? V ar(Out(Q))). Then Q is output-free. Proof. Immediate from the de nition of output-free sequence and the condition on the substitution .

2

Lemma 3.7 Let Q1 and Q2 be output-free and such that V ar(Q1 ) \ V ar(Out(Q2)) = ;. Then Q1Q2 is output-free. Proof. Immediate from the de nition of output-free sequence. 2 Lemma 3.8 Let P be a noFD program and Q a noFD query in P . Let us consider one non-trivial LD-derivation step Q j?!P Q0 . The query Q0 is also noFD. Proof. Q0 is well-typed by a Lemma in [4]. Let Q = B1 ; : : :; Bm , then Q0 = (C1 ; : : :; Cr ; B2 ; : : :; Bm ), where c : K C1 ; : : :; Cr : is the input clause used in the derivation step,  = mgu(K; B1 ) and c is standardized apart wrt Q. First we prove that Q0 is output-free. 4

 Q is output-free by De nition 3.4, then (i) V ar(Out(B ; : : :; Bm )) \ V ar(B ) = ;; 2

1

(ii) B2 ; : : :; Bm is output-free; (iii) B1 is output-free;  c is noFD, then (iv ) C1 ; : : :; Cr is output-free; (v) V ar(In(K )) \ V ar(Out(C1 ; : : :; Cr )) = ;;  c is standardized apart wrt Q and  is idempotent and relevant, hence (vi) V ar() \ V ar(Q)  V ar(B1 ); (vii) V ar() \ V ar(C1 ; : : :; Cr )  V ar(K ); (viii) V ar(Q) \ V ar(c) = ; and  = jQ  jc . Then,  by (i) and (vi), V ar() \ V ar(B2 ; : : :; Bm )  (V ar(In(B2 ; : : :; Bm )) ? V ar(Out(B2 ; : : :; Bm ))); hence, by (ii) and Lemma 3.6, (ix) (B2 ; : : :; Bm ) is output-free.  by (iii), (viii) and the fact that  = mgu(K; B1), (x) V ar(jc ) \ (V ar(Out(K )) ? V ar(In(K ))) = ;. Hence by (vii), (viii), (x), (xi) V ar(jc ) \ V ar(C1 ; : : :; Cr )  V ar(In(K )), and from (v), (xii) V ar(jc ) \ V ar(C1 ; : : :; Cr )  (V ar(In(C1 ; : : :; Cr )) ? V ar(Out(C1 ; : : :; Cr ))). Then, by (iv), (xii), Lemma 3.6 and (viii), (xiii) (C1 ; : : :; Cr )jc = (C1 ; : : :; Cr ) is output-free.  by (i) and (vi), Out(B2 ; : : :; Bm ) = Out((B2 ; : : :; Bm )), and by (viii), (xiv) V ar((C1 ; : : :; Cr )) \ V ar(Out(B2 ; : : :; Bm )) = ;. Then by (ix), (xiii), (xiv) and Lemma 3.7, Q0 is output-free. Let us consider now the second condition of noFD queries. (C1 ; : : :; Cr ; B2 ; : : :; Bm ) is output-free, then for any atom D in (C1 ; : : :; Cr ; B2 ; : : :; Bm ) and for any substitution such that D is an input-correct and output-free instance of D, there exists D0 in C1 ; : : :; Cr ; B2 ; : : :; Bm and a substitution 0 such that D = D0 0 and D0 0 is an input-correct and output-free instance of D0 . Hence the second condition for noFD queries immediately follows from the fact that P and Q are noFD. 2 Theorem 3.9 Let P be a noFD program and Q a noFD query in P . Then Q cannot have nitely failing derivations. Proof. We prove that for any noFD query Q and any natural number n, if Q has a nite LD-derivation of length n then it is a successful derivation. The proof can be given by induction on n. n = 1. Q j?!P R. By contradiction let us assume R = fail. Hence the rst atom of Q can unify with no clause in P . But Q is noFD in P , hence well-typed, and its rst atom, B1 , is then correctly typed in input positions and output-free. By the third property in De nition 3.3, we have a contradiction for = . Hence nite derivations of one step can only be successful ones.  2 R. n > 1: Let us distinguish the rst step in the derivation: Q j?!1P Q0 j?! P 0 is still a noFD query. Then, by inductive hypothesis By Lemma 3.8 we know that the rst resolvent Q 2 R, we have the thesis. 2 applied to Q0 j?! P Note that our conditions for being noFD are only sucient to guarantee absence of FDs. They are clearly not necessary, in fact the query Q = app([1]; [2]; Zs); app([1]; [2]; Zs) is not noFD, since it does not satisfy 5

the rst condition in De nition 3.4 (output-freeness), but it does not have FDs. On the other hand the fact of being noFD clearly does not imply anything on termination. Let us consider the query p(a; Y ) and the trivial program p(X,Y) p(X,b).

p(X,Y).

with directional type p(+ : Const; ? : Const). Both the query and the program are noFD but the query has an in nite LD-tree. What we can safely claim is that all nite LD-derivations in such a tree are successful. The class of noFD programs and queries is very restrictive, in fact outputs cannot be compound terms. For example the queries Q1 = app([0; 1; 2]; [3]; [0 j Xs]) and Q2 = app([0; 1; 2]; [3]; [X j Xs]), which do not have FDs, are not noFD. Another case which is not captured is exempli ed by the query app([X; 1; 2]; [3]; [X j Xs]) which is not in the noFD class since V ar(In(B1 )) \ V ar(Out(B1 )) = fX g and then the rst condition in De nition 3.4 is not satis ed. But this query clearly does not have FDs! In order to capture also the previous examples, it would be nice to weaken the rst syntactic condition in De nition 3.4. Unluckily there seems to be no easy way to do it. Let us consider for example the nitely failing query app([1; 1; 2]; [3]; [a j Xs]). As soon as we allow for compound terms in output, we have to face these cases. The well-typing condition is not sucient to ensure absence of FDs, we would need to impose semantic conditions such as the ones given in [3]. Namely we should require that for all substitutions such that Bi is an input-correct and output-free instance of Bi , there exist such that Bi 2 MP , where MP is the least Herbrand model of P . Since our goal is to de ne a static analysis technique for determining absence of FDs, we do not want to have "semantic" conditions. Moreover, and more seriously, test queries cannot be in the noFD class. In fact for a test query the last condition in De nition 3.4 cannot be satis ed for all input-correct instances since the purpose of a test is just to act as a lter. As a simple example let us consider the noFD program: test(a,a). test(a,b). test(c,c).

with directional type test(+ : Const; ? : Const) and the query test(b; Y ). Clearly such a query cannot satisfy the second condition! As another example consider the simple query Q = app([1]; Y s; Zs); Y s 6= [2; 3]. Clearly the second atom in this query cannot satisfy the second condition. For this reason, all generate-and-test programs are automatically excluded from the class of noFD programs, as well as all the programs which use tests. In section 5 we introduce a larger class of programs for which a weaker property is guaranteed, namely if the query universally terminates, then there exists at least one successful LD-derivation. These programs can use tests in their de nition.

Example 3.10 1) Let us consider the following program sumlist([ ], 0). sumlist([X Xs], SX) sum(0, X, X). sum(s(X), Y, s(Z))

j

sumlist(Xs, S), sum(S, X, SX). sum(X, Y, Z).

The predicate sumlist(x1; x2 ) de nes the relation between a list of natural numbers, x1 , and a natural number, x2 , which is the sum of the elements of the list. The directional types are sumlist(+ : ListNat; ? : Nat) and sum(+ : Nat; + : Nat; ? : Nat). The predicate sumlist is noFD. In order to prove it we observe that it is well-typed and then we consider the two recursive clauses in the de nition of sumlist and sum. 6

Let us consider the clause sumlist([X j Xs]; SX ) sumlist(Xs; S ); sum(S; X; SX ): The rst two syntactic conditions in De nition 3.3 are trivially satis ed. For the third one: let us consider 1 such that sumlist(Xs; S ) 1 is input-correct and with S 1 new variant of S . Then Xs 1 2 List, namely either it is an empty list or a non-empty one. In the rst case sumlist(Xs; S ) 1 uni es with the rst clause in the de nition of sumlist, in the second case with the second clause. Let us consider the clause sum(s(X ); Y; s(Z )) sum(X; Y; Z ): The rst two syntactic conditions in De nition 3.3 are trivially satis ed. For the third one we have to consider 2 such that sum(X; Y; Z ) 2 is input-correct and with Z 2 new variant of Z . Then X 2; Y 2 2 Nat. Y 2 can unify with any clause in the de nition of sum, since the second term in both the clauses is a variable. X 2 is either 0 or s(N ), with N 2 Nat. In the rst case it can unify with the rst clause in the de nition of sum, in the second case with the second clause. 2) Let us consider a few programs taken from [28]. Wrt the speci ed directional types, they are all noFD. prefix([ ], Ys). prefix([X Xs], [X Ys])

j

j

prefix(Xs, Ys).

with directional type prefix(? : List; + : List); suffix(Xs, Xs). suffix(Xs, [Y Ys])

j

suffix(Xs, Ys).

with directional type suffix(? : List; + : List); length([ ], 0). length([X Xs], s(N))

j

length(Xs, N).

with directional type length(+ : List; ? : Nat); reverse([ ], [ ]). reverse([X Xs], Zs)

j

reverse(Xs, Ys), append(Ys, [X], Zs).

with directional type reverse(+ : List; ? : List) and app(+ : List; + : List; ? : List); preorder(void, [ ]). preorder(tree(X, L ,R), Xs) preorder(R, Rs), append([X Ls], Rs, Xs).

preorder(L, Ls),

j

with directional types preorder(+ : Btree; ? : List) and app(+ : List; + : List; ? : List). hanoi(s(0), A, hanoi(s(N), A, hanoi(N, C, append(Ms1,

B, B, B, [A

C, C, A, to

[A to B]). Moves) hanoi(N, A, C, B, Ms1), Ms2), B Ms2], Moves).

j

with directional type preorder(+ : Nat; + : Pegs; + : Pegs; + : Pegs; ? : List), where Pegs = fa; b; cg. 3) Let us consider the well-known program quicksort: quicksort([ ], [ ]). quicksort([X Xs], Ys) partition(Xs, X, Littles, Bigs), quicksort(Littles, Ls), quicksort(Bigs, Bs), app(Ls, [X Bs], Ys). partition([ ], X, [ ], [ ]). partition([Y Xs], X, [Y Littles], Bigs) Y X, partition(Xs, X, Littles, Bigs). app([ ], Ys, Ys). app([X Xs] , Ys, [X Zs]) app(Xs, Ys, Zs).

j

j

j j

j

j

j

j

7

with directional types

quicksort(+ : ListNat; ? : ListNat), partition(+ : ListNat; + : Nat; ? : ListNat; ? : ListNat), app(+ : ListNat; + : ListNat; ? : ListNat). We already know that app is noFD. partition is not, since it has body atoms which are tests (Y  X; Y > X ). Hence also quicksort is not noFD. For similar reasons the following programs are not noFD. gcd(X, gcd(X, mod(X, mod(X,

0, Y, Y, Y,

X). Gcd) X) Z)

mod(X, Y, Z), gcd(Y, Z, Gcd). X=Y, X1 is X-Y, mod(X1, Y, Z).

with directional types gcd(+ : Int+ ; + : Int+ ; ? : Int+ ) and mod(+ : Int+ ; + : Int+ ; ? : Int+ ), where Int+ is the set of non-negative integers; fib(0,1). fib(1,1). fib(N, X) N>1, N1 is N-1, fib(N1, X1), N2 is N-2, fib(N2, X2), X is X1+X2.

with directional types fib(+ : Int+ ; ? : Int+ ) and is(? : Int+ ; + : Int+ ). delete([ ], X, [ ]). delete([X Xs], X, Ys) delete(Xs, X, Ys). delete([X Xs], Z, [X Ys]) X = Z, delete(Xs, Z, Ys).

j j

j

6

with directional type delete(+ : List; + : Any; ? : List); flatten([ ],[ ]). flatten(X, [X]) constant(X), X = [ ]. flatten([X Xs], Ys) flatten(X, Ys1), flatten(Xs, Ys2), app(Ys1, Ys2, Ys).

6

j

with directional types flatten(+ : List [ Const; ? : List) and app(+ : List; + : List; ? : List). Note that in this program app is noFD and flatten is not. If we consider now

j j

member(X, [X Xs]). member(X, [Y Ys])

member(X, Ys).

2

wrt any directional type this program is not noFD.

4 Applications

4.1 Program Correctness

Many techniques have been developed for proving properties of logic programs. Among the properties we usually want to prove are termination wrt a given query [6, 13, 27], partial correctness of the program wrt a given speci cation [19, 7, 16, 18, 4, 3, 23] and program completeness wrt a speci cation [7, 18, 3]. A di erence with imperative programmming, is that in logic programming partial correctness of a program wrt a given speci cation and universal termination of a query do not imply that the query has correct computed answer substitutions. In fact, as pointed out in [3], partial correctness and termination do not imply that there are actually correct results, because nite failures are ignored in the veri cation. For example we can prove the partial correctness of the app program wrt the Pre/Post speci cation 8

fx1; x2 2 Listgapp(x1; x2; x3)fx1; x2; x3 2 Listg. This is exactly the same as proving well-typing of app wrt the directional type app(+ : List; + : List; ? : List). It means that if app is invoked with the rst two terms x1; x2 which are lists and if it successfully terminates, then the c.a.s. will be such that also the third term, x3, is a list. We can also prove that the query app([1]; [1; 2]; [1; 2]) universally terminates in app since such a proof basically depends on the groundness of the rst list. We can prove that it is partially correct wrt an appropriate instance of the same Pre/post speci cation, namely f[1]; [1; 2] 2 Listgapp([1]; [1; 2]; [1; 2])f[1]; [1; 2]; [1; 2] 2 Listg. But nevertheless the query has only a nitely failing LD-derivation. This cannot be seen in the veri cation process and it is due to the fact that correctness proofs are inductive and they ignore failures. When the Pre-condition is satis ed for an atom in a clause body or in a query, if the atom succeeds then the proof method assumes that the Post-condition holds. In order to state that there are correct solutions to our query, we need to know also that there are actually successful derivations. To this purpose the following Corollary can be used.

Corollary 4.1 Let P be a noFD program and Q a noFD query in P . If Q universally terminates, then 2

it has at least a successful derivation.

Hence in order to be sure that there are correct c.a.s. we can verify: universal termination of the query + partial correctness of the program and the query + the noFD property of both. Clearly proving the noFD property is stronger than what we actually need. In fact being noFD and universally terminating implies absence of nite failures, while it would be enough to know that there is at least one successful LD-derivation. But this is in general more dicult to prove, as we will see in the next section, while the noFD property is rather easy to prove statically and the proof can be automatized.

Example 4.2 1) Let us consider the app program with the usual directional type app(+ : ListNat; + : ListNat; ? : ListNat) and the well-typed query Q = app([1; 2]; [3; 5]; Zs); app(Zs; [6; 8]; Y s).

We can prove, with one of the existing techniques, that:  app(l1; l2; l3) is partially correct wrt the Pre/Post speci cation fl1; l2 2 Listg=fl3 = l1  l2g;  the query universally terminates and it is also partially correct wrt the same Pre/Post speci cation. Since we know that both app and Q are noFD, we can state also that l3 is actually correctly computed. Moreover we can claim that the computation of the correct result l3 is ecient, namely it contains no failing sub-computation. 2) Let us consider again the program for computing the sum of the elements of a list: sumlist([ ], 0). sumlist([X Xs], SX) sum(0, X, X). sum(s(X), Y, s(Z))

j

sumlist(Xs, S), sum(S, X, SX). sum(X, Y, Z).

with directional types sumlist(+ : ListNat; ? : Nat) and sum(+ : Nat; + : Nat; ? : Nat). Let us consider the well-typed query sumlist([1; 2; 3; 4; 5; 6]; N ). We can P prove that the program sumlist(ls; s) is partially correct wrt the Pre/Post speci cation: fls 2 Listg=fs = ei , with ei 2 lsg. We can prove that the query is universally terminating and partially correct wrt the same Pre/Post speci cation. But since the program and the query are noFD, we can actually state that there is a c.a.s. (N = 21). As in the previous example we can also state that the computation of N is ecient, since it contains no failing sub-computation. 2

4.2 Program Transformation

When dealing with Prolog programs the order of atoms in the clauses is relevant, as a consequence program transformation techniques become much more restrictive in order to preserve the semantics. The major diculties are due to replacement, a very general transformation operation used to replace a sequence of atoms in a clause body with another (equivalent) sequence [29, 22, 26, 20, 11, 24]. The 9

switching operation, which switches two adiacent atoms in a body, is just a special case of replacement. It is often necessary to reorder the body atoms for applying other transformations such as folding. In [8] we de ne a safe transformation sequence, based on new-de nition, unfolding and folding, which preserves c.a.s. and universal termination of Prolog programs. Such safe transformation sequence includes a decreasing unfolding step which is necessary in order to prevent folding from introducing loops. For characterizing decreasing unfolding in [8] we state the following Lemma which requires to verify absence of FDs. Lemma 4.3 ([8]) Let c : N A; B; C: be the only clause in P de ning the predicate symbol of N . Let be a substitution such that V ar( ) \ V ar(c)  V ar(N ) and A has no failing derivation in P . Then, unfolding B in c in P is decreasing wrt G = fN g. 2 Clearly unfolding the leftmost atom in c is decreasing. But we can now ensure the requirement of the Lemma also on non-trivial A by verifying that A is a noFD query in a noFD program. Hence the noFD property gives the possibility of unfolding also atoms which are not leftmost while preserving universal termination. In [10] we extend the safe transformation sequence by adding the replacement operation and state an applicability condition such that it also preserves both c.a.s. and universal termination. De nition 4.4 [Safe replacement wrt typing [10]] Let B and B0 be sequences of atoms, P a welltyped program and c : H A; B; C: a clause in P . Let X be the set of common variables and Y the set of private variables in B and B0 . Replacing B with B0 in c is safe wrt P and its typing i  it is syntactically safe, that is the variables in Y are local wrt c and c0 :

V ar(H; A; C) \ Y = ;; for all substitutions  such that V ar() \ V ar(c)  V ar(H; A), Var () \ Y = ; and c is well-typed,

 the well-typing is preserved, namely c0  is also well-typed;

 B and B0 are equivalent in c wrt P : M[ P ] (B)jX = M[ P ] (B0 )jX ;

 B0 is non-increasing in c wrt B in P : for any nite LD-derivation l0 : B0  j?! P R, where either R = 2 or R = fail, there exists a corresponding nite LD-derivation l : B j?! P R, with X0  X, which is not shorter: j l jj l0 j. 2 0

The last two conditions are in general not computable and often dicult to verify. For the third one it is possible to use program transformation techniques, while the last one usually requires inductive proofs which can be dicult in presence of FDs. If the two sequences of atoms involved in the replacement are noFD, the veri cation of the applicability condition can be greatly simpli ed. Here is a concrete example of transforming a program by a safe transformation sequence which uses two kinds of replacement, associativity of a predicate and switch. Example 4.5 Here is a transformation exploiting a predicate with associative property, namely the sum operation on natural numbers. Let us consider again sumlist(x1; x2 ): sumlist([ ], 0). sumlist([X Xs], SX) sum(0, X, X). sum(s(X), Y, s(Z))

j

sumlist(Xs, S), sum(S, X, SX). sum(X, Y, Z).

10

with directional types sumlist(+ : ListNat; ? : Nat) and sum(+ : Nat; + : Nat; ? : Nat). We can prove, with one of the known techniques [6, 13, 27], that both the well-typed queries sumlist(x; y) and sum(x1; x2; x3) universally terminate. Moreover have already veri ed that, wrt the speci ed directional types, the program is noFD. We apply now the extended safe transformation sequence de ned in [8, 10] in order to linearize sumlist with the accumulation technique. i) We add a new de nition for introducing the accumulator: d: sacc(L, Tot, Acc)

sumlist(L, SX), sum(SX, Acc, Tot).

with the induced directional type sacc(+ : ListNat; ? : Nat; + : Nat). sacc is well-typed and it universally terminates. Note that the new clause is noFD. In order to optimize sacc we apply the following transformations: ii) unfold the rst atom sumlist in d (decreasing unfold): sacc([ ], Tot, Acc) sum(0, Acc, Tot). sacc([X Xs], Tot, Acc) sumlist(Xs, S), sum(S, X, SX), sum(SX, Acc, Tot).

j

iii) unfold the rst clause and apply the associative property of sum to the second clause, namely replace B = sum(S; X; SX ); sum(SX; Acc; Tot) with B0 = sum(X; Acc; T ); sum(S; T; Tot). This is a safe replacement wrt its typing by De nition 4.4. In fact it is easy to verify that the replacement is syntactically safe and it preserves the well-typing. Moreover in the following two Lemmas we prove the validity of the other two conditions required by De nition 4.4. Lemma 4.6 B and B0 are equivalent in the second clause, c, wrt the program.

Proof

This can be proved by transformation [25, 24] as follows. Since  in De nition 4.4 cannot modify fSX; T g, we can apply to B our safe transformation sequence. i) We de ne d: p1(S, X, Acc, Tot)

sum(S, X, SX), sum(SX, Acc, Tot).

with directional type p1(+ : Nat; + : Nat; + : Nat; ? : Nat), d is well-typed and the well-typed instances of d exactly correspond to the instances B of De nition 4.4. ii) We unfold the leftmost atom in d. It is a decreasing unfold. 1: p1(0, X, Acc, Tot) sum(X, Acc, Tot). 2: p1(s(X'), X, Acc, Tot) sum(X', X, SX'), sum(s(SX'), Acc, Tot).

iii)

We unfold clause 1 and the second atom in clause 2. 3: p1(0, 0, Acc, Acc). 4: p1(0, s(X'), Acc, s(Tot')) 5: p1(s(X'), X, Acc, s(Tot'))

iv)

sum(X', Acc, Tot'). sum(X', X, SX'), sum(SX', Acc, Tot').

We apply fold to clause 5, thus obtaining the nal program: 3: p1(0, 0, Acc, Acc). 4: p1(0, s(X'), Acc, s(Tot')) 5: p1(s(X'), X, Acc, s(Tot'))

sum(X', Acc, Tot'). p1(X', X, Acc, Tot').

We now apply the safe transformation sequence to B0 . i) We de ne d: p2(S, X, Acc, Tot)

sum(X, Acc, T), sum(S, T, Tot).

11

with directional type p2(+ : Nat; + : Nat; + : Nat; ? : Nat), d is well-typed and the well-typed instances of d exactly correspond to the instances B0  of De nition 4.4. ii) We unfold the second atom in d. By Lemma 4.3, this is a decreasing unfold wrt G = fp2(S; X; Acc; Tot) g for all which can be applied in an LD-derivation to d, when used as input clause. In fact for all substitutions such that V ar( ) \ V ar(d)  fS; X; Acc; Totg and d well-typed, we have that T = T and then sum(X; Acc; T ) cannot fail. This can be obtained as a consequence of the fact that sum(X; Acc; T ) is universally terminating and noFD. 1: p2(0, X, Acc, Tot) sum(X, Acc, Tot). 2: p2(s(X'), X, Acc, s(Tot')) sum(X, Acc, T), sum(X', T, Tot').

iii-iv)

We unfold clause 1 and then fold clause 2 thus obtaining the nal program:

3: p2(0, 0, Acc, Acc). 4: p2(0, s(X'), Acc, s(Tot')) 5: p2(s(X'), X, Acc, s(Tot'))

sum(X', Acc, Tot'). p2(X', X, Acc, Tot').

The two programs obtained by B and B0 through a safe transformation sequence are identical modulo predicate renaming. In this way we proved that B and B0  are equivalent wrt our semantics and wrt their common variables for all instances  as required in De nition 4.4. 2 We should now verify the last condition in De nition 4.4. Lemma 4.7 B0 is non-increasing in c wrt B in P . We should then analyze both successful and failing LD-derivations of B0 and B. But the original program de ning sum is noFD and the tranformation steps performed until now did not modify the de nition of sum. We can prove that the queries B and B0 are noFD. Hence by Theorem 3.9 we know that B and B0 have no nitely failing LD-derivations, which allows us to consider only successful LD-derivations of B and B0 . First of all we state the following property. Successful derivations of a well-typed query sum(X; Y; Z ) have length j X j +1. This can be easily proved by induction on j X j. Then successful derivations of B0  have length j X j +1+ j S j +1 =j X j + j S j +2 and successful derivations of B have length j S j +1+ j SX j +1 =j S j +1 + (j S j + j X j) + 1 = 2 j S j + j X j +2. Hence the non-increasing property of De nition 4.4 is satis ed. 2 Note also that the program resulting from this transformation step is still noFD:

Proof

sacc([ ], Acc, Acc). sacc([X Xs], Tot, Acc)

j

sumlist(Xs, S), sum(X, Acc, T), sum(S, T, Tot).

- switch sumlist(Xs; S ) and sum(X; Acc; T ). It is a safe replacement wrt its typing by De nition 4.4. In fact the replacement is syntactically safe and it preserves the well-typing. Moreover  in De nition 4.4 cannot modify fS; T g, then we can prove that B and B0  are universally terminating, noFD queries. This allows us to prove, in a rather simple way, both that they are equivalent in the second clause wrt the program and that B0 is non-increasing in the clause wrt B. In fact the two atoms in B cannot share variables since they are both ground in the input terms and S = S; T = T . Hence the two atoms in B are independent, universally terminating and noFD. Clearly switching them has no e ect on the length and the c.a.s. of their LD-derivations. Note that the resulting program is still noFD: sacc([ ], Acc, Acc). sacc([X Xs], Tot, Acc)

j

iv)

sum(X, Acc, T), sumlist(Xs, S), sum(S, T, Tot).

fold with d in sacc de nition: 12

sacc([ ], Acc, Acc). sacc([X Xs], Tot, Acc)

j

sum(X, Acc, T), sacc(Xs, Tot, T).

The resulting program is still noFD. v) fold with d in the original de nition of sumlist: sumlist([ ], 0). sumlist([X Xs], SX) sacc([ ], Acc, Acc). sacc([X Xs], Tot, Acc)

j

j

sacc(Xs, SX, X). sum(X, Acc, T), sacc(Xs, Tot, T).

This is the nal program and the optimized through the accumulation technique.

2

This example shows that, if we know that the sequences of atoms we deal with in a replacement are noFD, we can greatly simplify the veri cation of the replacement applicability condition. Furthermore, as exempli ed in the equivalence proof given in the Appendix, the noFD property gives the possibility of unfolding also atoms which are not leftmost while preserving universal termination. Even if the noFD condition is very restrictive, we generally need to verify it only on some predicates, namely the ones to which we want to apply a speci c transformation operation. On the other hand sometimes we could be interested in preserving the noFD property through the various transformation operations. Let us brie y consider them. When we introduce a new de nition which refers to noFD predicates, we have to impose on it the further requirements given by our De nition 3.3, so that the extended program is also noFD. In our example we de ne sacc which refers to sumlist and sum, which are both noFD predicates. The new de nition d is also noFD. Leftmost unfold unconditionally preserves the noFD property. This is a consequence of Lemma 3.9. On the contrary general unfold preserves neither the noFD property nor absence of FDs, as shown by the following example. Example 4.8 Let us consider the trivial program: 1: p(X, q(b, r(b, r(a,

Z) a). T). T).

q(X, Y), r(Y, Z).

with directional types: p(+ : fbg; ? : Any); q(+ : fbg; ? : fag); r(+ : fa; bg; ? : Any). The program is well-typed and noFD. By unfolding the second atom in clause 1 we obtain the following program. 2: p(X, Z) 3: p(X, Z) q(b, a). r(b, T). r(a, T).

q(X, b). q(X, a).

This program is no more noFD since clause 2 does not satisfy the rst syntactic condition (outputfreeness). Moreover clause 2, when used as input clause in an LD-derivation, produces a nitely failing derivation.

2

Let us now consider replacement. In general we need to require that also the resulting clause is noFD. But for some special cases of replacement it is sucient to require only part of the conditions in De nition 3.3, as shown in the following discussion. 13

Fold is a special case of replacement. Let us assume that we fold a noFD clause c : H A; B; C: by using a new de nition d which is also noFD and let d : K B: Then by de nition of fold [8], the replacement of B with K in c is syntactically safe and preserves well-typing. The only property we need to require is that K is output-free. In fact it is sucient that Out(K ) = V ar(Out(K )); if X1 ; : : :; Xk are the output terms in K , then Xi 6= Xh , for i 6= h, i; h 2 [1; k] and Out(K ) \ V ar(In(K )) = ;; in order to be able to prove that (c : H A; B; C: is noFD) implies (c0 : H A; K; C: is noFD). Note that in our example both d and fold with d clearly satisfy the condition. The associativity of a predicate is also a special case of replacement. This replacement naturally preserves the property of being noFD. In fact let B = (p(X 1; X 2; T ); p(T; X 3; Z )) and B0 = (p(X 2; X 3; V ); p(X 1; V; Z )), where p is an associative predicate, such as sum or app, with moding (+; +; ?) and  is a well-typed input substitution with Dom(jB ) = Dom(jB ) = fX 1; X 2; X 3g. By de nition of replacement, when the associativity is applicable it must be syntactically safe and preserve well-typing. Hence it is easy to prove that (B is a noFD query) i (B0 is a noFD query) and then also (c : H A; B; C: is noFD) i (c0 : H A; B0 ; C: is noFD). Switch is also a special case of replacement. Let c : H C; A; B; D: Switching A and B in c is clearly syntactically safe and, in order to be applicable, it has to preserve well-typing. Hence we need to impose only the further condition Out(A) \ V ar(B ) = ;. In fact if this is veri ed, we have that (c : H C; A; B; D: is noFD) implies (c0 : H C; B; A; D: is noFD). Note that when the two atoms A and B do not share variables, as in our example, the condition is already veri ed and then the noFD property is naturally preserved through switching. 0

5 Successful Programs In Section 3 we have seen how using tests in a program prevents it to be noFD. Tests predicates sometimes produce ineciency, as in generate-and-test programs, and then it is better to avoid them. But often they are necessary, as in a sorting algorithm. We would like to be able to state some property on successful derivations also on these programs. We then de ne a class which is wider than the one of noFD programs and which characterizes a weaker property: the programs in the class can have FDs but they are guaranteed to have at least one successful derivation. We call it the class of successful programs. De nition 5.1 [Exaustive tests] Let P be a well-typed program wrt the directional types T and let p be a predicate de ned in P by the clauses p(ti ) Ti ; Bi :, with i 2 [1; m]. T1; : : :; Tm are exaustive tests for p wrt input types in T i for any well-typed input substitution for p, , namely such that p(X) is an input-correct and output-free instance of p(X), there exists i, i 2 [1; m], such that  = mgu(p(X); p(ti )) and Ti  has at least one successful LD-derivation. 2

Example 5.2 Let us consider the following trivial program p(X, Y, p(a, B, p(b, a, p(b, c, any(b). any(c). r(X, Y)

Z) Z) Z) Z)

X = Y, r(1, Z). any(B), r(2, Z). r(3, Z). r(4, Z).

...

14

with directional types:

T = p(+ : fa; bg; + : fa; b; cg; ? : R); any(+ : fa; b; cg); r(+ : f1; 2; 3; 4g; ? : R). Then fX = Y; any(B ); true; trueg are exaustive tests for p wrt input types in T . In fact well-typed input substitutions  for p(X 1; X 2; X 3) are such that X 1 2 fa; bg and X 2 2 fa; b; cg.

Let us consider all possible cases. 1)  = fX 1=a; X 2=ag or  = fX 1=b; X 2=bg, then  = mgu(p(X; Y; Z ); p(X 1; X 2; X 3)), with  = fX=a; Y=ag or  = fX=b; Y=bg and in both cases the test (X = Y ) is successful. 2)  = fX 1=a; X 2=bg or  = fX 1=a; X 2=cg, then  = mgu(p(X; B; Z ); p(X 1; X 2; X 3)), with  = fX=a; B=bg or  = fX=a; B=cg and in both cases the test any(B ) is successful. 3)  = fX 1=b; X 2=ag, then  = mgu(p(b; a; Z ); p(X 1; X 2; X 3)), with  = ; and the test true is successful. 4)  = fX 1=b; X 2=cg, then  = mgu(p(b; c; Z ); p(X 1; X 2; X 3)), with  = ; and the test true is successful. Since for any well-typed input substitution  the condition in De nition 5.1 is satis ed, the tests are exaustive. 2 Note that we can always introduce a dummy test true in a clause in order to associate a set of exaustive tests to a predicate p with types in T . For example when p is de ned also by facts, the introduction of the dummy test \true" is necessary for satisfying De nition 5.1. De nition 5.3 [Successful predicate] Let P be a well-typed program wrt the directional types T . Let p(ti ) Ti ; Bi :, with i 2 [1; m], be the clauses de ning a predicate p in P . A predicate in P is successful wrt the input types in T i for all the predicates p in the deductive closure of its de nition in P 1. T1 ; : : :; Tm are exaustive tests for p wrt input types in T ; 2. (noFD conditions) for i 2 [1; m]  the sequence Bi is output-free;  V ar(Out(Bi ) \ (V ar(In(p(ti ))) [ V ar(Ti )) = ;;  for all D 2 Bi and for any input-correct and output-free instance D of D, there exists a clause in P whose head uni es with D . P is a successful program wrt the input types in T i it de nes only successful predicates, wrt the input types in T . 2 The intuitive idea is that if p is a successful predicate, for any query p(t), input-correct and output-free, there is at least a clause in the de nition of p which is applicable, whose tests are successful and which produces a non- nitely failing derivation (noFD conditions on the atoms in the body which follow the tests). Note that we require that tests are leftmost in the clause bodies. This is clearly a restriction, since tests can appear also in other positions. For example let us consider a non-tail recursive de nition of the maximum element in a list of integers. On the other hand this requirement simpli es the de nition of successful programs. Note also that if p is a noFD predicate and for any well-typed input substitution , p(X) is a noFD query, then p is also a successful predicate. In fact we can always introduce the dummy test true in all the clauses de ning p. On the other hand the predicate is de ned for any well-typed input, hence we have tests which are trivially exaustive. Example 5.4 Let us consider again the append program app([ ], Ys, Ys). app([X Xs], Ys, [X Zs])

j

j

app(Xs, Ys, Zs).

15

with the directional type app(+ : List; + : List; ? : List). This is a successful program. In fact we can add the dummy test true as the leftmost atom in the body of both the clauses. Now ftrue; trueg are exaustive tests for app wrt app(+ : List; + : List; ). Since app is noFD we know that also the noFD conditions on the body atoms are veri ed. 2 For successful programs we can prove that any noFD query which universally terminates in P has at least one successful derivation. Theorem 5.5 Let P be a successful program wrt the input types in T and Q a noFD query in P . If Q is universally terminating in P , then it has at least one successful LD-derivation in P . Proof. Let us assume that Q is universally terminating in P , then it has a nite LD-tree in P . The proof can be given by induction on the depth n of the LD-tree for a universally terminating, noFD query Q. n = 1. By contradiction let us assume that all the derivations have the form Q j?!P fail. Hence the rst atom of Q can unify with no clause in P . But Q is noFD, hence well-typed, and its rst atom is then input-correct and output-free. By the third property in De nition 3.3, we have a contradiction for = . n > 1: Let Q = B1 ; : : :; Bn . Since P is successful and Q is noFD, hence well-typed, and its rst atom is then input-correct and output-free, there exists a clause ci : p(ti ) Ti ; Ci : in P , i 2 [1; m], standardized apart wrt Q, and a substitution  such that:  = mgu(B1; p(ti )) and Ti  has at least one successful LD-derivation. Then, there exists the derivation Q j?!P R, where R = (Ti ; Ci ; B2 ; : : :; Bn ) and R is not empty. Let be a computed answer substitution for Ti , we have the LD-derivation: Q j?!P R j?! P Q0, with Q0 = (Ci; B2; : : :; Bn) . We prove that Q0 is noFD. Then, by inductive hypothesis applied to Q0 , we have the thesis.  Since P is successful and Q a noFD query, Ci and B2 ; : : :; Bn are output-free sequences. We assumed standardization apart and is a c.a.s. for Ti , then  V ar( ) \ V ar(B2 ; : : :; Bm )  V ar(B1 ). But Q is output-free, then V ar(Out(B2 ; : : :; Bm )) \ V ar(B1 ) = ;, hence V ar( ) \ V ar(B2 ; : : :; Bm )  (V ar(In(B2 ; : : :; Bm )) ? V ar(Out(B2 ; : : :; Bm ))) and, by Lemma 3.6, (i) (B2 ; : : :; Bn ) is output-free and (ii) Out(B2 ; : : :; Bm ) = Out(B2 ; : : :; Bm ).  V ar( ) \ V ar(Ci )  V ar(p(ti ); Ti ). Moreover V ar(ci ) \ V ar(Q) = ; and  = jc  jQ . Since  = mgu(B1; p(ti )) and B1 is output-free, we have that V ar(jc )\(V ar(Out(p(ti )))?V ar(In(p(ti )))) = ;. Then V ar(jc ) \ V ar(Ci )  V ar(In(p(ti ))) and V ar(jc ) \ V ar(Ci )  V ar(In(p(ti )); Ti ). Hence, since P is successful, V ar(jc ) \ V ar(Ci )  (V ar(In(Ci )) ? V ar(Out(Ci ))) and, by Lemma 3.6, (iii) Ci jc = Ci  is output-free.  V ar(Ci  )\V ar(Q ))  V ar(B1  ). Because of (ii) we have also that V ar(B1  )\V ar(Out((B2 ; : : :; Bm ) )) = ;. Then, (iv) V ar(Ci  ) \ V ar(Out((B2 ; : : :; Bm ) )) = ;. Then, by (i), (iii), (iv) and Lemma 3.7, Q0 is output-free. Let us now prove that Q0 satis es also the second condition for noFD queries. (Ci ; B2 ; : : :; Bm ) is output-free, then for any atom D in (Ci ; B2 ; : : :; Bm ) and for any input-correct and output-free instance D there exist D0 in Ci ; B2 ; : : :; Bm and a substitution 0 such that D = D0 0 , and hence D0 0 is a input-correct and output-free instance of D0 . Hence the second condition for noFD queries immediately follows from the fact that P is successful and Q is noFD. 2 Not many programs can satisfy our De nition 5.3. One reason is that often the directional type associated to a predicate is actually larger than the type for which the predicate has been de ned. Hence we can extend De nition 5.3 by introducing the notion of actual input types. i

i

i

i

i

i

16

De nition 5.6 [Actual input types] Let P be a well-typed program and p a predicate de ned in P by the clauses p(ti ; : : :; tin ; si ; : : :; sir ) Bi :, with i 2 [1; m], where tik , k 2 [1; n], indicate input terms and sih , h 2 [1; r], output terms. Let Tk , for k 2 [1; n], be the types associated to the input positions in the directional type of p. The actual input types of p, ATk , for k 2 [1; n], are given by the sets of all the instances of terms in the k-th input positions of the heads of the de nitions of p which belongs to Tk : ATk = ([ ft k ; : : :; tmk g) \ Tk . 2 Example 5.7 Let us consider the predicate de ning the last element of a list: 1

1

1

last([X], X). last([X, Y Xs], Z)

j

j with the directional type last(+ : List; ? : Any).

last([Y Xs], Z).

The actual input type of last is: AT1 = ([ f[X ] ; [X; Y j Xs] g) \ List, namely the set of non-empty lists: List ? f[ ]g. This program is noFD, as one can easily verify. Nevertheless it is not successful. Let us introduce two dummy tests true, leftmost in the clauses, as usual. Such tests are not exaustive, in fact De nition 5.1 requires that also for the query last([]; Y ), which is well-typed in input, there is at least a unifying clause with a successful test. But last is not de ned for empty lists. 2 The actual input type is a subset of the input type declared in the directional type. It is the set of terms which can be e ectively used as input when querying the predicate. The de nitions of exaustive tests and successful predicate can be given wrt actual input types. In this case the condition on exaustive tests in De nition 5.1 is simpli ed since there always exists a clause i 2 [1; m] and an mgu  for any well-typed input substitution. Another diculty in using De nition 5.3 is the identi cation of exaustive tests. To make it easier we introduce now a transformation for normalizing input arguments in a program. De nition 5.8 [Input-normalized de nition] Let P be a well-typed program and p(i1; : : :; in; o1; : : :; or ) a predicate de ned in P , where ik , with k 2 [1; n], are the input positions and oh , with h 2 [1; r] the output positions in p. Let V = fX1 ; : : :; Xng be a set of new variables wrt p, namely variables which do not appear in the de nition of p. The input-normalized de nition of p, pN , is the program obtained by substituting each clause in the de nition of p p(t1 ; : : :; tn ; s1 ; : : :; sr ) B: with the corresponding input-normalized clause p(X1 ; : : :; Xn ; s1 ; : : :; sr ) X1 = t1 ; : : :; Xn = tn ; B: The program thus obtained is input-normalized wrt p. V is the set of normalized input variables for pN . Xk = tk , for k 2 [1; n], are the input equalities in each clause in the de nition of pN . 2 Lemma 5.9 Let P be a well-typed program and p a predicate de ned in P . Let us associate in pN , to each input equality Xk = tk , the directional type = (+ : Tk ; ? : Tk ), where Tk is the type associated to the k-th input position in the directional type of p. Then pN is well-typed. Proof. Trivial, by De nition of well-typed clause. 2 N Lemma 5.10 Let P be a well-typed program and p a predicate de ned in P . p is clause-wise equivalent to p. Proof. By unfolding the input equalities in each clause in pN , we obtain the clauses of p again. On the other hand we already proved [8] that unfolding preserves both c.a.s. and universal termination. 2 Note that the property of being noFD is not preserved through input-normalization. In fact even if the original predicate p is noFD, pN can be non-noFD since in general input equalities do not satisfy the output-free condition in De nition 3.3. 17

Example 5.11 Let us de ne appN wrt the directional type app(+ : List; + : List; ? : List). X1 , X 2 , X1 , X 2 ,

app( app(

Ys) [X Zs])

j

X1

X

= [ ], 2 = Ys. 1 = [X Xs],

X

j

X2

= Ys, app(Xs, Ys, Zs).

appN is not noFD. It does not satisfy the rst syntactic condition in De nition 3.3 since compound terms are in output in the input equalities in the clause bodies. 2 We assume that input-normalized programs always refer to the actual input types of the original program. In fact a query with input terms in the actual input types of the original program will satisfy the corresponding input equalities in the input-normalized version. Example 5.12 Let us consider the input-normalized version of the program in the example 5.7, lastN :

X1 , X1 ,

last( last(

X) Z)

X1 X1

= [X]. = [X, Y Xs], last([Y Xs], Z).

j

j

If the query has a non-empty list in input, namely its input term is in the actual input type of the original program, then one of the input equalities succeeds. 2 We give here the de nitions of exaustive tests and successful program extended in order to consider actual input types and normalization. These extended conditions are generally easier to verify that the ones in the previous De nitions 5.1 and 5.3. De nition 5.13 [Exaustive tests (extended)] Let P be a well-typed program, p a predicate de ned in P and AT = (AT1 ; : : :; ATn ) its actual input types. Let pN be its input-normalized version p(X1 ; : : :; Xn ; si ) Ti ; Bi :, with i 2 [1; m], and V = fX1 ; : : :; Xng be the set of normalized input variables for pN . T1; : : :; Tm are exaustive tests (for pN ) wrt AT i for all well-typed input substitutions  wrt AT, namely such that Dom() = V and Xk  2 ATk , for k 2 [1; n], there exists i, i 2 [1; m], such that Ti  has at least one successful LD-derivation. 2 Often we can verify that a set of predicates are exaustive tests wrt a type without any need to refer to a speci c program and predicate. Example 5.14 1) Let V = fX; Y g, AT = (Nat; Nat) and T1 = (X > Y ); T2 = (X  Y ), where the directional type of both the inequality relations is (+ : Nat; + : Nat). T1; T2 are exaustive tests wrt AT since for any input substitution wrt AT ,  = fX=n1; Y=n2g, with n1 ; n2 2 Nat, either n1 > n2 or n1  n2 is successful. 2) Let us consider V = fN g, AT = (Int+ ) and T1 = (N = 0); T2 = (N = 1); T3 = (N > 1), with directional type (+ : Int+ ; + : Int+ ) for all the relations. These are exaustive tests wrt AT since for any value of N in Int+ , one of them is successful. 3) Let V = fX; Z g, AT = (Type; Type) and T1 = (X = Z ); T2 = (X 6= Z ), with directional type (+ : Type; + : Type) for both equality and inequality. These are exaustive tests wrt any Type since uni cation is decidable. 2

De nition 5.15 [Successful predicate (extended)] Let P be a well-typed program.

A predicate in P is successful wrt its actual input types i for all the predicates p in (the deductive closure of) its de nition in P the following conditions are satis ed. Let AT be the actual input types for p and let p(ti ) Ti ; Bi :, with i 2 [1; m], be the clauses de ning the input-normalized version pN in P . 1. T1 ; : : :; Tm are exaustive tests for pN wrt AT ; 2. (noFD conditions) for i 2 [1; m]  the sequence Bi is output-free;  V ar(Out(Bi )) \ (V ar(In(p(ti ))) [ V ar(Ti )) = ;; 18

 for all D 2 Bi and for any input-correct wrt AT and output-free instance D of D, there

exists a clause in P whose head uni es with D . P is a successful program wrt actual input types i it de nes only successful predicates wrt their actual input types. 2 In order to verify that a program is successful we need to verify the property of having exaustive tests. This is a semantic condition, but in most practical cases the conditions in De nition 5.15 can be easily veri ed as shown in the following examples. Note that by the previous de nition, we can determine tests predicates by composing the input equalities introduced by input-normalization with atoms in the clause bodies for which conditions in De nition 3.3 are not satis ed. Example 5.16 Let us consider the well-typed programs given in Section 3 as examples of programs which are not noFD. 1) Now we see that quicksort is successful wrt actual input types. quicksort([ ], [ ]). quicksort([X Xs], Ys) partition(Xs, X, Littles, Bigs), quicksort(Littles, Ls), quicksort(Bigs, Bs), app(Ls, [X Bs], Ys). partition([ ], X, [ ], [ ]). partition([Y Xs], X, [Y Littles], Bigs) Y X, partition(Xs, X, Littles, Bigs). app([ ], Ys, Ys). app([X Xs] , Ys, [X Zs]) app(Xs, Ys, Zs).

j

j

j j

j

j

j

j

with directional types quicksort(+ : ListNat; ? : ListNat), partition(+ : ListNat; + : Nat; ? : ListNat; ? : ListNat), app(+ : ListNat; + : ListNat; ? : ListNat). partition is not noFD, let us consider its actual input types and then normalize it. The actual input types can be obtained by the de nition of partition, they are: AT = (([ f[ ] ; [Y j Xs] g) \ ListNat; ([ fX g) \ Nat), which means AT = (ListNat; Nat). The normalized version of partition is:

X X X X

X

partition( 1, 2 , [ ], [ ]) 1 = [ ], partition( 1, 2 , [Y Littles], Bigs) partition(Xs, X, Littles, Bigs). partition( 1 2 , Littles, [Y Bigs]) partition(Xs, X, Littles, Bigs).

X ;X

j

j

X2 = X. X1 = [Y jXs], X2 X1

j

= [Y Xs],

X2

= X, Y X,

The two atoms (Y X ) do not satisfy the conditions for body atoms in De nition 3.3. Hence the set of tests we have to consider is: T1 = (X1 = [ ]; X2 = X ), T2 = (X1 = [Y j Xs]; X2 = X; Y X ). Let us consider the well-typed input substitution wrt AT :  = fX1 =t1; X2 =t2 g with t1 2 ListNat; t2 2 Nat. If t1 is an empty list the rst test T1 is successful. Otherwise t1 is a non-empty list of natural numbers, then Y; X 2 Nat and either Y X is successful. Hence the tests are exaustive for partition wrt AT . Let us consider the other (noFD) conditions for being successful. In each of the two recursive clauses the rst two syntactic conditions are satis ed. In fact output terms in the partition atom in the body, fLittles; Bigsg, are all distinct variables and they do not appear in 19

input in the head and leftmost in the body. For all substitutions such that Xs 2 ListNat; X 2 Nat and Littles ; Bigs are new variants of Littles; Bigs, there exists a clause in P whose head uni es with partition(Xs; X; Littles; Bigs) . In fact the value of Xs can be either an empty list or a non-empty list of naturals. In the rst case partition(Xs; X; Littles; Bigs) uni es with the rst clause in the de nition of partition, in the second case it uni es with both the second and the third clause in the de nition. 2) gcd, mod and fib are successful programs too. We omit the veri cation which is similar to the previous one. 3) Let us consider now delete. The actual input types are AT = (([ f[] ; [X j Xs] g) \ List; ([ fZ g) \ Any), namely AT = (List; Any). After input-normalization we obtain:

X ;X X ;X

delete( 1 2 , [ ]) delete( 1 2 , Ys) delete(Xs, X, Ys). delete( 1 2 ,[X Ys]) delete(Xs, Z, Ys).

X ;X

X1 = [ ], X2 = X. X1 = [X jXs], X2 =

j

j

X1

= [X Xs],

Z, X = Z,

X2

= Z, X

6=

Z,

The built-in predicates have a directional type which is induced by the well-typing condition, namely equality and inequality have directional type (+ : Any; + : Any). The program is successful. Let us consider the set of tests: T1 = (X1 = [ ]; X2 = X ), T2 = (X1 = [X j Xs]; X2 = Z; X = Z ), T3 = (X1 = [X j Xs]; X2 = Z; X 6= Z ). Let us consider a well-typed input substitution  wrt AT . Either  maps X1 into an empty list and the rst test T1 is successful, or it maps X1 into a non-empty list and then X; Z 2 Any and one of the two atoms (X = Z ); (X 6= Z ) is successful. The other two (noFD) conditions are easy to verify on the recursive atoms. 4) Let us consider flatten. AT = ([ f[] ; X ; [X j Xs] g) \ (List [ Const), namely AT = (List [ Const). After input-normalization we obtain:

X X X

X X X

flatten( 1, [ ]) 1 = [ ]. flatten( 1, [X]) 1 = X, constant(X), X = [ ]. flatten( 1, Ys) 1 = [X Xs], flatten(X, Ys1), flatten(Xs, Ys2), app(Ys1, Ys2, Ys).

6

j

The built-ins have directional type 6= (+ : List [ Const; ? : List [ Const), constant(+ : List [ Const). Let us consider the set of tests: T1 = (X1 = [ ]), T2 = (X1 = X; constant(X ); X 6= [ ]), T3 = (X1 = [X j Xs]) Let us consider a well-typed input substitution  wrt AT .  maps X1 either into an empty list, then the rst test T1 is successful, or into a constant which is not an empty list, then the second tests is successful, or into a non-empty list and then the third test is successful. The other two (noFD) conditions on the recursive clause are easy to verify. 2 In order to make easier to prove the property of being exaustive tests for a predicate, it can be useful to \simplify" the set of clauses we consider. To this purpose we introduce the following de nition. De nition 5.17 [Clause input-subsumed by a fact or a clause] Let P be a well-typed program. Let c1 : A: be a fact, c2 : H B: and c3 : K A: be clauses in P which de ne the same predicate, namely A = p(t1 ), H = p(t2 ) and K = p(t3 ). Clause c2 is input-subsumed by the fact c1 i there exists an input substitution  such that A = H . Clause c3 is input-subsumed by clause c2 i there exists an input substitution  such that H = K . 2 20

Example 5.18 Let us consider the trivial well-typed program 1: 2: 3: 4: 5: 6:

p(X, Y). p(a, Y) p(X, b) p(a, b) r(b). s(b).

r(a), s(Y). r(X). r(a), p(a, Y).

with directional types p(+ : Const; ? : Const); r(+ : Const); s(? : Const). Clause 2 is input-subsumed by fact 1. Clause 4 is input-subsumed by clause 3.

2

We have extended the usual concept of subsumption to t the veri cation of the successful property. We are not interested in c.a.s. but in characterizing the presence of at least one successful derivation for each well-typed input substitution. A fact always produces a successful derivation, then it can input-subsume a clause independently from its body. Similarly for two clauses, if the one accepting a more general input produces a successful derivation, then the other one becomes irrelevant. Input-subsumption can be used to prune the program. If we can prove that a pruned de nition of a predicate is successful, then also the original de nition is successful. This means that we may simplify the veri cation of De nition 5.15 by rst pruning the program of some input-subsumed clauses. The simpli cation phase must be applied before input-normalization. After input-normalization inputsubsumption becomes trivial. If we have two clauses which input-subsume each other and one of them is noFD, it is more convenient to keep the noFD clause and prune the other one. In fact for the simpli ed set of clauses resulting from input-normalization it may be easier to verify the exaustive property on tests. We can further extend our de nition of successful programs in the following way. A program is successful i by pruning some input-subsumed clauses it satis es De nition 5.15. Given a program P , the nite failure analysis could proceed as follows:  if the program P is noFD (De nition 3.3) then OK;  else repeat { prune P by eliminating some input-subsumed clauses and determine actual input types; { input-normalize the resulting program; { single out the tests in the bodies fthe input equalities plus the atoms whose output terms do not satisfy the (noFD) conditions on body atoms in De nition 3.3g; until (such tests are exaustive) and (the other (noFD) conditions in De nition 5.15 are veri ed). Hence we need to use De nition 5.15 only when the simpler De nition 3.3 does not apply. Note that tests usually belong to one of the following classes:  arithmetic tests, as in the quicksort; mod; gcd examples;  equalities and inequalities in the Herbrand universe, as in the delete example;  built-ins, as in the flatten example. Hence we could a-priori characterize interesting sets of exaustive tests. The property of beeing successful, even if weaker than the one of being noFD, can be useful in the eld of program veri cation. Let us assume to have a program which is partially correct wrt a speci cation and a query which is both universally terminating and partially correct wrt the speci cation. Then, if we prove that the program is successful and the query is noFD, Theorem 5.5 ensures the existence of at least one correct c.a.s. 21

Also in the eld of program transformations being successful can be useful. In [12] we consider leftterminating programs [5] and we de ne a sucient condition for switching atoms in the clause bodies while preserving left-termination. This condition for switching the atom A with B in a clause c : H J; A; B; K: depends on the property of A of being \non-failing", namely for each grounding substitution , such that Dom() = V ar(In(H ); J; In(A)) and J 2 MP , there exists such that A 2 MP . This intuitively means that if A is the selected atom in an LD-derivation, because c was used as input clause in a previous derivation step, then the computation of A will eventually succeed. This is a \semantic" condition which is not easy to verify in general. But if we prove that the de nition of A in the program is successful and that the query A is universally terminating and noFD, then the non-failing condition is guaranteed. Example 5.19 Let us consider an example of transformation given in [12]. The following program de nes the predicate goodpath(X; Xs) which relates a node X with a list Xs of \good" nodes which are connected to X . ... 1: path(X, [X]). 2: path(X, [X Xs]) 3: goodlist([ ]). 4: goodlist([X Xs]) d: goodpath(X, Xs)

j

j

arc(X, Y), path(Y, Xs). good(X), goodlist(Xs). path(X, Xs), goodlist(Xs).

The directional types are

path(+ : Const; ? : List); goodlist(+ : List); goodpath(+ : Const; ? : List) arc(+ : Const; ? : Const); good(+ : Const). The predicates good and arc are test predicates de ned in the program.

In [12] we consider a transformation which repeatedly applies unfold to the body atoms in d until we get to the following program: . . . d1:goodpath(X, [X]) good(X). d2:goodpath(X, [X Xs]) arc(X, Y), path(Y, Xs), good(X), goodlist(Xs).

j

In order to optimize the program by folding with d, we need to switch path(Y; Xs) and good(X ) in d2. In [12] we proved that the switching is allowed if  path(Y; Xs) is \old", namely it has not been transformed,  V ar(In(good(X )))  (V ar(In(goodpath(X; [X j Xs]))) [ V ar(arc(X; Y )) and  path(Y; Xs) is non-failing in d2. The rst two conditions are trivially true. For the third one we can prove that  for each grounding substitution , such that Dom() = fX; Y g and Y  2 Const, path(Y; Xs) is a noFD query, which is trivial, and  path is a successful predicate. In fact let us consider the de nition of path: 1: path(X, [X]). 2: path(X, [X Xs])

j

arc(X, Y), path(Y, Xs).

We can prune 2, since it is input-subsumed by the fact 1. Hence we obtain a noFD program: 1: path(X, [X]).

which implies that the de nition of path is successful. 22

2

6 Conclusion We have de ned the class of programs and queries without failures (noFD) [9] which have the property of not having nitely failing derivations. It can be useful both for verifying program properties and for program transformation. Such a class is very restricted but usually it is sucient that only some of the predicates in the program are in the class. We have de ned also the wider class of successful programs which includes also programs using tests. noFD queries for successful programs have the property of having at least one successful derivation, if they are universally terminating. This property is more complex to verify but it is less restrictive and still useful both for verifying program properties and for program transformation. Finitely failing LD-derivations, even if relevant in practice, are dicult to study and characterize. Previous studies have focused on the set of atoms which nitely fail. This could be used to characterize properties of negation-as-failures. In program veri cation and transformation we are actually interested in identifying both the queries which have some successful LD-derivations and those which have some nitely failing LD-derivations. Non-failure analysis is interesting also for parallel execution optimization. In [17] a method is given for detecting programs and queries which produce at least one solution or do not terminate. The method is based on a di erent notion of mode and type information and deals also with programs containing tests. Our proposal is clearly more restrictive, but also simpler to verify.

Acknowledgements

This work was supported partly by the Italian MURST with the National Research Project on \Modelli della Computazione e dei Linguaggi di programmazione" (40% funding) and partly by the Italian C.N.R. with the \Progetto Coordinato - Programmazione Logica: Strumenti per Analisi e Trasformazione di Programmi; Tecniche di Ingegneria del Software; Estensioni con Vincoli, Concorrenza, Oggetti".

References [1] K. R. Apt. Introduction to Logic Programming. In J. van Leeuwen, editor, Handbook of Theoretical Computer Science, volume B: Formal Models and Semantics. Elsevier, Amsterdam and The MIT Press, Cambridge, 1990. [2] K. R. Apt. Declarative programming in Prolog. In D. Miller, editor, Proceedings of the 1993 International Symposium on Logic Programming, pages 12{35. The MIT Press, 1993. [3] K. R. Apt. From Logic Programming to Prolog. Prentice Hall International Series in Computer Science, 1997. [4] K. R. Apt and E. Marchiori. Reasoning about Prolog programs: from modes through types to assertions. Formal Aspects of Computing, 6(6A):743{765, 1994. [5] K. R. Apt and D. Pedreschi. Studies in Pure Prolog: termination. In J.W. Lloyd, editor, Proceedings of the Simposium in Computational Logic, pages 150{176, Berlin, 1990. Springer-Verlag. [6] K. R. Apt and D. Pedreschi. Reasoning about termination of pure Prolog programs. Information and Computation, 106(1):109{157, 1993. [7] A. Bossi and N. Cocco. Verifying correctness of logic programs. In J. Diaz and F. Orejas, editors, TAPSOFT '89, Barcelona, Spain, March 1989, (Lecture Notes in Computer Science, vol. 352), pages 96{110. Springer-Verlag, 1989. [8] A. Bossi and N. Cocco. Preserving Universal Termination through Unfold/Fold. In G. Levi and M.Rodriguez-Artalejo, editors, Algebraic and Logic Programming - Proceedings ALP'94, volume 850 of Lecture Notes in Computer Science, pages 269{286. Springer-Verlag, Berlin, 1994. [9] A. Bossi and N. Cocco. Programs without Failures. In N. Fuchs, editor, Proceedings LOPSTR'97, Lecture Notes in Computer Science. Springer-Verlag, Berlin, 1997. 23

[10] A. Bossi and N. Cocco. Replacement Can Preserve Termination. In J. Gallagher, editor, Proceedings LOPSTR'96, volume 1207 of Lecture Notes in Computer Science, pages 104{129. Springer-Verlag, Berlin, 1997. [11] A. Bossi, N. Cocco, and S. Etalle. Transforming Normal Programs by Replacement. In A. Pettorossi, editor, Meta Programming in Logic - Proceedings META'92, volume 649 of Lecture Notes in Computer Science, pages 265{279. Springer-Verlag, Berlin, 1992. [12] A. Bossi, N. Cocco, and S. Etalle. Transformation of Left Terminating Programs: The Reordering Problem. In M. Proietti, editor, Proceedings LOPSTR'95, volume 1048 of Lecture Notes in Computer Science, pages 33{45. Springer-Verlag, Berlin, 1996. [13] A. Bossi, N. Cocco, and M. Fabris. Norms on terms and their use in proving universal termination of a logic program. Theoretical Computer Science, 124:297{328, 1994. [14] J. Boye and J. Maluszynski. Two Aspects of Directional Types. In Sterling, editor, Proc. Int'l Conf. on Logic Programming, pages 747{761. MIT Press, 1995. [15] F. Bronsard, T. K. Lakshman, and U. S. Reddy. A framework of directionalities for proving termination of logic programs. In K. R. Apt, editor, Proceedings of the Joint International Conference and Symposium on Logic Programming, pages 321{335. The MIT Press, 1992. [16] L. Colussi and E. Marchiori. Proving Correctness of Logic Programs using axiomatic semantics. In Proc. Eighth Int'l Conf. on Logic Programming, pages 629{644. MIT Press, 1991. [17] S. Debray, P. Lopez-Garcia, and M.Hermenegildo. Non-Failure Analysis for Logic Programs. In Proceedings of the International Symposium on Logic Programming, pages 48{62, 1997. [18] P. Deransart. Proof Methods of Declarative Properties of De nite Programs. Theoretical Computer Science, 118:99{166, 1993. [19] W. Drabent and J. Maluszynski. Inductive assertion method for logic programs. Theoretical Computer Science, 59:133{155, 1988. [20] P.A. Gardner and J.C. Shepherdson. Unfold/fold Transformations of Logic Programs. In J-L Lassez and editor G. Plotkin, editors, Computational Logic: Essays in Honor of Alan Robinson. 1991. [21] J. W. Lloyd. Foundations of Logic Programming. Springer-Verlag, Berlin, 1987. Second edition. [22] M.J. Maher. Correctness of a Logic Program Transformation System. IBM Research Report RC13496, T.J. Watson Research Center, 1987. [23] D. Pedreschi and S. Ruggeri. Veri cation of Metainterpreters. Journal of Logic and Computation, 7(2), 1997. [24] A. Pettorossi and M. Proietti. Transformation of Logic Programs: Foundations and Techniques. Journal of Logic Programming, 19(20):261{320, 1994. [25] M. Proietti and A. Pettorossi. Synthesis of Programs from Unfold/Fold Proofs. In Y. Deville, editor, LOPSTR'93, pages 141{158, 1994. [26] T. Sato. An equivalence preserving rst order unfold/fold transformation system. In Second Int. Conference on Algebraic and Logic Programming, Nancy, France, October 1990, (Lecture Notes in Computer Science, Vol. 463), pages 175{188. Springer-Verlag, 1990. [27] D. De Schreye and S. Decorte. Termination of Logic Programs: the never-ending story. Journal of Logic Programming, 19-20:199{260, 1994. [28] L. Sterling and E. Shapiro. The Art of Prolog. The MIT Press, 1986. [29] H. Tamaki and T. Sato. Unfold/Fold Transformations of Logic Programs. In Sten- Ake Tarnlund, editor, Proc. Second Int'l Conf. on Logic Programming, pages 127{139, 1984. 24

Suggest Documents