A First Order Logic of Effects - CiteSeerX

Report 9 Downloads 71 Views
A First Order Logic of Effects Ian A. Mason May 30, 1996

Abstract In this paper we describe some of our progress towards an operational implementation of a modern programming logic. The logic is inspired by the variable type systems of Feferman, and is designed for reasoning about imperative functional programs. The logic goes well beyond traditional programming logics, such as Hoare’s logic and Dynamic logic in its expressibility, yet is less problematic to encode into higher order logics. The main focus of the paper is too present an axiomatization of the base first order theory.

1

Introduction

VTLoE [34, 23, 35, 37, 24] is a logic for reasoning about imperative functional programs, inspired by the variable type systems of Feferman. These systems are two sorted theories of operations and classes initially developed for the formalization of constructive mathematics [12, 13] and later applied to the study of purely functional languages [14, 15]. VTLoE builds upon recent advances in the semantics of languages with effects [16, 19, 28, 32, 33] and goes well beyond traditional programming logics, such as Hoare’s logic [7] and Dynamic logic [22] by treating a richer language and expressing more properties. It is close in spirit to Specification Logic [49] and to Evaluation Logic [44]. The underlying programming language of VTLoE, mk , is based on the call-by-value lambda calculus extended by the reference primitives mk, set, get. Atoms, references and lambda abstractions are all first class values – they can be bound to lambda variables, stored, and returned from procedures. It can thus be thought of as a fragment of untyped ML or a variant of Scheme. The logic combines the features and benefits of equational calculi as well as program and specification logics. There are three layers. The foundation is the syntax and semantics of mk , the underlying term/programming language. The second layer is a first-order theory built on assertions of program equivalence and program modalities called contextual assertions. The third layer extends the logic to include class terms, class membership, and quantification over class variables. In this paper we concentrate on the first two layers. The main topic of this paper is the presentation of a Hilbert style formal system for VTLoE and the proof of its completeness. Contextual assertions were first introduced in [31] as a means for expressing constraint propogation. It was quickly realized that they are an essential feature of any language for reasoning about the effects of programs. In our earlier work on axiomatizing imperative features [30, 29, 33] we presented a simple sequent system for proving equations. The introduction rules for the allocation and updating primitives were complicated by ugly side conditions. Conditions so ugly as to make the implementation of the system unfeasible. The main result of this paper is to generalize these previous results to a full first order language with contextual assertions. The crucial point is that contextual assertions eliminate the need for any side conditions.

1.1

Overview and Notation

The remainder of this paper is organized as follows. In x2 we introduce the syntax and semantics of the terms of VTLoE. In x3 we introduce the syntax and semantics of the formulas of VTLoE. In x4 we present the proof theory of VTLoE. In x5 we relate the semantics with the proof theory.  Department of Mathematics & Computer Science, University of New England, Armadale, N.S.W, Australia 2350

1

We conclude the introduction with a summary of notation. Let X; Y; Y0; Y1 be sets. We specify meta-variable conventions in the form: let x ranges over X , which should be read as: the meta-variable x and decorated variants such as x0 , x0, ..., range over the set X . We use the usual notation for set membership and function application. Y n is the set of sequences of elements of Y of length n. Y  is the set of finite sequences of elements of Y . y = [y1 ; : : :; yn] is f the sequence of length n with ith element yi . P! (Y ) is the set of finite subsets of Y . Y0 ! Y1 is the set of finite maps from Y0 to Y1 . [Y0 ! Y1 ] is the set of total functions f with domain Y0 and range contained in Y1 . We write Dom(f) for the domain of a function and Rng(f) for its range. For any function f , f fy := y0 g is the function f 0 such that Dom(f 0 ) = Dom(f) [ fyg, f 0 (y) = y0 , and f 0 (z) = f(z) for z 6= y; z 2 Dom(f). N = f0; 1; 2; : ::g is the natural numbers and i; j; n; n0; : : : range over N.

2

The Syntax and Semantics of Terms

2.1

Syntax

The syntax of the terms of mk is a simple extension of the lambda calculus to include basic atomic data A , (such as the Lisp S booleans t and nil, and in practice the natural numbers N), together with a collection of primitive operations, F = n2 Fn , where Fn is the (possibly empty) set of n-ary operations.

N

Booleans Recognisers Unary Operations Binary Operations Ternary Operations

ft; nilg  A T= fatom?; cell?; lambda?g F1 = fmk; getg [ T F2 = fapp; eq; setg F3 = fbrg

The primitive operations include: the memory operations ( mk,get,set) for allocating, dereferencing, and updating unary cells; the usual operations for strict branching ( br) and arithmetic; the recognizing operations ( atom?, cell?, lambda?) (or characteristic functions using the booleans t and nil) of their respective domains. We also treat application, app, as a binary operation for the sake of uniformity. Togther with the atoms, A , we assume an infinite set of variables, Xand use these to define, by mutual induction, the set of -abstractions, L, the set of value expressions, V, the set of value substitutions, S, the set of expressions, E , and the set of contexts, C , as the least sets satisfying the following equations:

a ranges over A Variables X x; y; z ranges over X Lambda Expressions L = X:E x:e ranges over L Value Expressions V= X+ A + L v ranges over V Value Substitutions S= X! V  ranges over S Expressions E = V+ Fn (En ) e ranges over E n Contexts C = fg + X+ A + X:C + Fn (C ) C ranges over C  is a binding operator and free and bound variables of expressions are defined as usual. FV(e) is the set of free variables of e. A value substitution is a finite map  from variables to value expressions, we let  range over value substitutions. e is the result of simultaneous substitution of free occurrences of x 2 Dom() in e by (x). We represent the function which maps x to v by fx := vg. Thus efx:=vg is the result of replacing free occurrences of x in e by v (avoiding the capture of free variables in v). Contexts are expressions with holes. We use  to denote a hole. C[e] denotes the result of replacing any holes in C by e. Free variables of e may become bound in this process. Traps(C) is the set of variables that can actually be trapped in the process of filling the holes in C. Atoms

A

f

2

2.2

Abbreviations

In order to make programs easier to read, we introduce some abbreviations.

4 = 4 letfx := e0 ge1 = 4 seq(e) = 4 seq(e0 ; : : :; en) = 4 if(e0 ; e1 ; e2) = 4 not(e) = 4 and(e0 ; e1) = 4 and(e0 ; e1; : : :en ) = 4 or(e0 ; e1 ) = 4 or(e0 ; e1 ; : : :en ) =

f(x)

2.3

(f; x) app(x:e1; e0 ) e letfz := e0 gseq(e1 ; : : :; en) app(br(e0 ; z:e1; z:e2 ); nil) if(e; nil; t) if(e0 ; e1 ; nil) and(e0 ; and(e1 ; : : :; en)) if(e0 ; t; e1) or(e0 ; or(e1 ; : : :; en)) app

z

62 FV(ei ) for i  n

for z fresh

Programming Examples

2.3.1

Equality on Cells

To simplify matters later we have omitted equality on cells as a primitive operation. It is however easily definable.

4 x:y:if(and(cell?(x); cell?(y)); ?= letfx0 := get(x); y0 := get(y)g seq(set(x; nil); set(y; t); letfz := get(x)g seq(set(x; x0); set(y; y0 ); z)); nil)

eq

2.3.2

Landin’s Recursion Operator

Since the mk -calculus extends the call-by-value -calulus the usual call-by-value fixed point combinator is a termm in the language. A somewhat different fixed point combinator, that makes use of the reference primitives, is possible: Y

4 y:letfz := mk(nil)g = seq(set(z; x:app(app(y; get(z)); x)); get(z))

This version of the fixed-point combinator is essentially identical to the one suggested by Landin [27]. When applied to a functional F of the form f:x:e, Y creates a private local cell, z , with contents G = x:app(app(F; get(z)); x), and returns G. By privacy of z , G is equivalent to F(G) (cf. [32]). Note that this example is typable in the simply typed lambda calculus (for provably non-empty types (cf. [24])). Thus adding operations for manipulating references to the simply typed lambda calculus causes the failure of strong normalization as well as many other of its nice mathematical properties. 3

2.3.3

Integer Streams

From an abstract point of view, a stream is simply a (possibly infinite) sequence of data [2]. In the mk -calculus we can represent streams simply as functional objects. The sequence corresponding to a mk -stream is the values reurned by repeated application of the object to a fixed (and hopefully irrelevant argument). The simplest example of a non-trivial mk -stream is the stream of natural numbers.

4 m:letfz := mk(m)g = x:letfn := get(z)g seq(set(z; n + 1); n) Here makeStream applied to an integer m creates a stream of integers beginning with that integer. makeStream

The so-created

stream when queried (applied to any value) returns the next integer in the stream. 2.3.4

The Sieve of Eratosthenes

A somewhat more interesting example of a stream is the sieve of Eratosthenes [2]. We begin with the functional filter which expects an integer, n, and a stream, s and then creates a new stream. This new stream when queried repeatedly calls the stream argument, s, until an integer not divisible by the number argument, n, is returned. This number is then returned as the answer to the query. filter

=4 n:s: x:letfm := s(nil)g if(divides?(n; m) filter(n; s)(nil) m)

sieve is an expression which when evaluated creates a new the sieve of Eratosthenes. This new stream is a stream of the prime numbers. Each time the stream is queried it returns the current prime and updates its local stream to filter with this prime. sieve

2.4

4 letfsc := mk(makeStream(2))g = x:letfs := get(sc)gletfp := s(nil)g seq(set(sc; filter(p; s)); p)

Semantics of Terms



The operational semantics of expressions is given by a reduction relation 7! on a syntactic representation of the state of an abstract machine, referred to as computation descriptions. A state has three components: the current instruction, the current continuation, and the current state of memory. Their syntactic counterparts are redexes, reduction contexts, and memory contexts respectively. Redexes describe the primitive computation steps. A primitive step is either a v reduction or the application of a primitive operation to a sequence of value expressions. The set of redexes, E r , is defined as Er

= Fn (Vn)

Reduction contexts identify the subexpression of an expression that is to be evaluated next, they correspond to the standard reduction strategy (left-first, call-by-value) of [46] and were first introduced in [18]. The set of reduction contexts, R, is the subset of C defined by R=

fg + Fm+n+1 (Vm; R; En ) 4

We let R ranges over R. An expression is either a value expression or decomposes uniquely into a redex placed in a reduction context. An easy structural induction establishes that if e 2 E , then either e 2 Vor e can be written uniquely as R[e0] where R 2 R and e0 2 Er . The set of memory contexts, M , is the set of contexts ? of the form

fz1 := mk(nil)g : : : letfzn := mk(nil)gseq(set(z1 ; v1); : : :; set(zn ; vn); ) where zi = 6 zj when i 6= j . We include the possibility that n = 0, in which case ? = . We let ? ranges over M . let

We have divided the memory context into allocation, followed by assignment to allow for the construction of cycles. Thus, any state of memory is constructible by such an expression. We can view memory contexts as finite maps from variables to value expressions. Hence we define the domain of ? (as above) to be Dom(?) = fz1; : : :; zn g, and ?(zi ) = vi for 1  i  n. Two memory contexts are considered the same if they are the same when viewed as functions. Viewing memory contexts and finite maps, we define the modification of memory contexts, ?fz := mk(v)g, and the union of two memory contexts, (?0 [ ?1), in the obvious way. ? is the result of applying  to each value in the range of ?. The set of computations descriptions (briefly descriptions), D , is defined to be the set M  E . Thus a description is a pair with first component a memory context and second component an arbitrary expression. We do not require that the free variables of the expression be contained in the domain of the memory context. This allows us to define reductions uniformly in parameters that are not touched by the reduction step, and hence to provide a form of symbolic evaluation. We let ?; e ranges over D . A closed description is a description of the form ?; e where FV(e)  Dom(?). Value descriptions are descriptions whose expression component is a value expression, i.e. a description of the form ?; v. (?; e) = ? ; e .



Definition (7!): ( v ) (atom) (cell) (eq) (br) (mk) (get) (set)



The reduction relation 7! is the reflexive transitive closure of 7!. The clauses are:

?; R[app(x:e; v)] 7! ?; R[efx:=vg ]  ?; R[t] if v 2 A ?; R[atom?(v)] 7! ?; R[nil] if v 2 L [ Dom(?)  ?; R[t] if v 2 Dom(?) ?; R[cell?(v)] 7! ?; R[nil] if v 2 L [ A  R[t] if v0 = v1 , v0 ; v1 2 A , ?; R[eq(v0 ; v1)] 7! ?; ?; R[nil] else if v0 ; v1 2 Dom(?) [ L [ A .  R[v1] if v0 2 (A ? fnilg) [ L [ P[ Dom(?) ?; R[br(v0 ; v1; v2 )] 7! ?; ?; R[v2] if v = nil ?; R[mk(v)] 7! ?fz := mk(v)g; R[z] if z 62 Dom(?) [ FV(R[v]) ?; R[get(z)] 7! ?; R[v] if z 2 Dom(?) and ?(z ) = v ?; R[set(z; v)] 7! ?fz := mk(v)g; R[nil] if z 2 Dom(?)

Note that in the atom? and cell? rules if one of the arguments is a variable not in the domain of the memory context then the primitive reduction step is not determined. This is also the case in the eq, br, get, and set rules. Definition (# " l ): A closed description, ?; e is defined (written # ?; e) if it evaluates to a value description. A description is undefined (written " ?; e) if it is not defined. Two descriptions, ?; e0 and ?; e1 are equivalued (written ?; e0  ?; e1) if they are both undefined or have a commmon reduct (i.e. they both reduce to a particular description)

#(?; e) , (9?0 ; v0 )(?; e 7! ?0 ; v0 ) "(?; e) , : #(?; e) ?; e0  ?; e1 , (("(?; e0) ^ "(?; e1)) _ (9?0; e)(?; e0 7! ?0; e ^ ?; e1 7! ?0 ; e)) 5

For closed expressions e, we write # e to mean # ;; e, e0 l e1 to mean that # e0 iff # e1 , and e0  e1 to mean ;; e0  ;; e1. Some simple consequences of the computation rules are that reduction is functional modulo alpha conversion, memory contexts may be pulled out of reduction contexts, and computation is uniform in free variables, unreferenced memory and reduction contexts. Lemma (cr):

?0[e0 ] = ?1[e1 ] if ?; e 7! ?i ; ei for i < 2  (ii) R[?[e]] 7! ?; R[e] if FV(R) \ Dom(?) = ;. 0 0 (iii) ?; e 7! ? ; e ) (?; e) 7! (?0 ; e0 ) if Dom(?0 ) \ Dom() = ; = FV(Rng()) \ (Dom(?0 ) ? Dom(?)). (iv) ?; e 7! ?0 ; e0 ) (?0 [ ?); e 7! (?0 [ ?0); e0 if Dom(?0 ) \ Dom(?0 ) = ;. (v) ?; R[e] 7! ?0; R[e0] ) ?; R0[e] 7! ?0 ; R0[e0] if (Dom(?0 ) \ FV(R0 ))  Dom(?) In (cr.i) = is the usual notion of alpha equivalence. It makes explicit the fact that arbitrary choice in cell allocation is

(i)

the same phenomenon as arbitrary choice of names of bound variables.

2.5

Operational Equivalence of Terms

In this section we define the operational equivalence relation and study its general properties. Operational equivalence formalizes the notion of equivalence as black-boxes. Treating programs as black boxes requires only observing what effects and values they produce, and not how they produce them. Our definition extends the extensional equivalence relations defined by [40] and [46] to computation over memory structures. As shown by [3, 4, 9, 11, 25, 28, 32, 26, 38, 42, 45, 50, 51] operational equivalence and approximation can be characterized in various ways. Definition ( =): Two expressions are operationally equivalent, written e0 is defined iff C[e1 ] is defined.

 = e1 , if for any closing context C, C[e0]

e0  = e1 , (8C 2 C FV(C[e0 ]) = FV(C[e1 ]) = ;)(C[e0 ] l C[e1])

The operational equivalence is not trivial since the inclusion of branching implies that t and nil are not equivalent. By definition operational equivalence is a congruence relation on expressions:

Congruence :

e0  = e1 ) (8C 2 C )(C[e0 ]  = C[e1])

However it is not necessarily the case that substitution instances of equivalent expressions are equivalent even if the instantiating expressions always returns a value. As a counter-example we have if(cell?(x); eq(x; x); t)  = t but if(cell?(mk(t)); eq(mk(t); mk(t)); t)  = nil. The reason underlying this is that in the case of programs with effects, returning a value is not an appropriate characterization of definedness. In particular returning a value is not the same as being operationally equivalent to a value. This is in contrast to the purely functional case and is due to the presence of effects. For example, each of the following expressions always returns a value

(x)

?(x); get(x); x) but none is equivalent to a value, i.e. for no value expression v do we have e  = v for any of the above three expressions. mk

(

?(x); set(x; y); x)

if cell

(

if cell

The first has an allocation effect. The second has a write effect. The third has a read effect. In general it is very difficult to establish the operational equivalence of expressions. Thus it is desirable to have a simpler characterization of  =, one that limits the class of contexts (or observations) that must be considered. The main context lemma in this case is the following Theorem (ciu): e0  = e1 , (8?; ; R)(FV(?[R[ei ]]) = ; A proof of (ciu) appears in [32], and in [24]. 6

) (?[R[e0 ]] l ?[R[e1 ]]))

3

The Syntax and Semantics of Formulas

3.1

Syntax

The first order fragment of our logic is a minor generalization of classical first order logic. The atomic formulas assert the equivaluedness and operational equivalence of expressions. In addition to the usual first-order formula constructions, we add a let-assertion: if  is a formula, x a variable, and e an expression then letfx := eg[ ]] is a formula. Definition (W):

= (E  E) + (E  = E ) + (W ) W) + (letfX:= E g [ W] ) + (8X)(W) For typographical convenience we will let L range over the class of let contexts. Thus L denotes a generic member of letfX:= E g. W

3.2

Semantics

The meaning of formulas is given by a Tarskian satisfaction relation ? j= []. Definition (? j= []): Assume ?; ; ; ej satisfy FV( ) [ FV(ej )  Dom(?) for j we define the satisfaction relation ? j= [] by induction on the structure of :

? j= (e0  e1 )[] ? j= (e0  = e1 )[] ? j= (0 ) 1)[] ? j= letfx := eg[ ]][] ? j= (8x)[]

iff iff iff iff iff

< 2, and FV(?) = ;. Then

?; e0  ?; e1 (8R 2 R FV(R)  Dom(?))(?[R[e0 ]] l ?[R[e1 ]]) (? j= 0 []) implies (? j= 1 []) (?; e 7! ?0 ; v) implies ?0 j= [fx := vg]) (8v 2 V FV(v)  Dom(?))(? j= [fx := vg])

As is usual in logic we define the subsidary notions of validity and logical consequence as follows:

j=  0 j= 1 3.3

iff iff

(8?;  FV( )  Dom(?))(? j= []) j= 0 ) 1

Examples, Counterexamples and Caveats

Negation is definable, : is just  ) False, where False is any unsatisfiable assertion, such as t  = nil. Similarly conjunction, ^ , and disjunction, _ and the biconditional, , , are all definable in the usual manner. Note that termination and non-termination are simple abbreviations. Note that the let-assertion is a binding operator akin to 8. A simple example is the axiom which expresses the effects of mk:

(8z)(8y)(letfx := mk(z)g[ :(x  = y) ^ cell?(x)  = t ^ get(x)  = v]])

Note that there are at least two notions of definedness that we can express. We let # e abbreviate :(letfx := eg[ False] ) and " e abbreviate its negation letfx := eg[ False] ). A stronger notion of definedness is that of being equivalent (either via  or via  =) to a value. These two notions will be important later. We use the symbol ' to denote either of the binary relations in our logic,  = and . It is important to note that, unlike equality in first order logic, neither of these binary relations ( = nor ) is a congruence in the sense that e0 ' e1 ) C[e0 ] ' C[e1] is falsifiable (even when no trapping occurs). For example

(x) ' t ) app(seq(set(x; nil); z:z); get(x)) ' app(seq(set(x; nil); z:z); t) is obviously not valid. Similarly false is the related principle that  ) letfx := eg[ ]]. For example get(z) ' t ) letfx := set(z; nil)g[ get(z) ' t] get

7

is clearly not valid. Also along these lines is the observation that while

fx := eg[ e0 ' e1 ] ) letfx := eg[ e0] ' letfx := eg[ e1]

let

is valid, its converse is false. Since

fx := mk(0)gletfy := mk(0)g[x] ' letfx := mk(0)gletfy := mk(0)g[y] is valid, but letfx := mk(0)g[ letfy := mk(0)g[ x ' y]]] is not. let

3.3.1

Violation of Privacy

Rather than give the impression that everything is rosy, we point out the following problem raised in [37]. One seemingly desirable logical principle for contextual reasoning is to be able to replace the e by any operationally equivalent expression without changing the semantics of the contextual assertion letfx := eg[ ]]. In other words the following principle seems desirable:

e0  = e1 ) (letfx := e0 g[ ]] ,

fx := e1 g[ ]])

let

However, there are several ways in which this can fail in this logic. For example e0 may produce some garbage that e1 does not, and this garbage may be detectable via . For example letting

e0 = seq(mk(0); mk(0)) e1 = mk(0)  = (9y0 )(9y1 )(cell?(y0 )  = t ^ cell?(y1 )  = t ^ eq(y0 ; y1)  = nil) provides a counterexample. Another more troublesome counterexample relies on the fact that e0 and e1 may be equivalent due to the privacy of certain cells, however their privacy is not respected by the contextual assertion. A simple example of this is:

e0 = x0:x0 e1 = letfz := mk(x0:x0)gw:app(get(z); w) =x = y:y A simple induction on the length of computations (similar to those found in [32]) establishes that e0 and e1 are operationally equivalent, and hence e0  = e1 is valid. The essential observation is that the cell z is local to the value/object returned by e1 and thus invisible and its contents unalterable outside this scope. However it is not the case that

j= letfx := e0 g[ ]] ,

fx := e1 g[ ]]

let

However all is not lost, we do have that the weaker principle

e0  e1 ) (letfx := e0 g[ ]] ,

fx := e1 g[ ]])

let

is valid.

3.4

Extending the Syntax of Contextual Assertions

For simplicity we have minimalized the syntax of contextual assertions to simple let statements. In earlier treatments [24] we dealt with a much wider class of contexts, called univalent contexts, (U-contexts). They are the largest natural class of contexts whose symbolic evaluation is unproblematic. The key restriction is that we forbid the hole to appear in the scope of a (non-let) lambda, thus preventing the proliferation of holes. The class of U-contexts, U, is defined as follows. 8

Definition (U): U=

f  g + letfX:= E g U+ if(E ; U; U)+ Fm+n+1 (Em ; U; En )

The semantics is a simple generalization of the one presented here, and the curious are refered to [24] for details. The main reason for restricting our attention to let contexts, apart from the simplicity in presentation, is that those left out may be considered abbreviations: (0) R[[]] abbreviates . (1) seq(e1 ; e2 ; : : :; en; [ ]]) abbreviates

fx1 := e1 g[ : : :[[letfxn := en g[ ]]] : : :]]

let

provided xi are fresh.

(2) letfx1

(3)

(4)

:= e1 ; : : :; xn := en g[ ]] abbreviates letfx1 := e1 g[ : : :[[letfxn := en g[ ]]] : : :]] provided xi 62 FV(ej ) for 1  i < j  n. if(e0 ; [ 0] ; [ 1] ) abbreviates letfz := e0 g[ (z  = nil ) 1 ) ^ (:(z  = nil) ) 0 )]] z fresh: #(e0 ; : : :; en ; U[[]]; en+1; : : :) abbreviates seq(e0 ; : : :; en; U[[]])

That these abbreviations are in fact sound derive from theorem (ca.iii) in [24] which states that (in this generalized semantics): Theorem (ca): (iii)

4

U0 [ U1[ ]]] , (U0 [U1])[[]] Proof Theory

Since contextual assertions are akin to modalities, we give a Hilbert style presentation. In the long run a natural deduction style system in the style of Prawitz [47] may be more desirable. Definition (` ): The consequence relation, `, is the smallest relation on W that is closed under the rules given below. The rules are partitioned into several groups. Each group of rules is given a label, for future reference, and members of the group are numbered. For example (E.i) refers to the first rule in the group of equivalence and evaluation rules (the second group below). A rule has a (possibly empty) set of premisses and a conclusion. In the case that the set of premisses is non-empty the rule is displayed with a horizontal bar separating the premisses from the conclusion. Variable Convention: We adopt Barendregt’s convention [8] that in any particular mathematical situation the bound and free variables in expressions are distinct. However we do (and must) allow free variables of expressions to coincide with bound (trappable) variables in contexts. So for example we assume in: (E.vi) that x not free in R; (E.vii) that x 62 FV(e); (C.v) that x 62 FV(); (Q.ii) that x 62 FV(0 ); (mk.ii) and (mk.iii) that x 62 FV(e0 ); and in (S.i) that x 62 z. On the other hand in in (mk.i) we must explicitly state that the variable x is distinct from the variables y and z . This convention makes the statement of (Q.i) somewhat cumbersome. Most axioms hold true for both equivaluedness, , and operational equivalence,  =, If this is the case, then rather than write out the principle twice, we use the symbol ' to range over these two equivalence relations. One important reason for introducing  is that important principles fails for  =. In particular (C.iii) below fails as indicated in [37] and in x3.3.1. 9

4.1

Basic Equivalence Axioms and Rules

The first, most basic axiom concerning operational equivalence and equivaluedness is that the booleans t and nil are not equivalent. Non-Triviality (T).

(i) ` :(t ' nil) The second set of rules concerning equivaluedness hold true also of operational equivalence. They are equivalence relations, (E.i, E.ii, E.iii). They satisfy a certain restricted form of substitutivity, (E.iv). And are preseved under simple forms of evaluation, (E.v, E.vi, E.vii), these last three principles are (equivalent to) the let-rules of the lambda-c calculus [39]. Equivalence and Evaluation rules (E).

(i) ` e0 ' e0 (ii) ` (e0 ' e1 ^ e1 ' e2 ) ) e0 ' e2 (iii) ` e0 ' e1 ) e1 ' e0 (iv) ` e0 ' e1 ) letfx := e0 ge ' letfx := e1 ge (v) ` app(x:e; v) ' efx:=vg ' letfx := vge (vi) ` R[e] ' letfx := egR[x] (vii) ` letfx := e0 gletfy := e1 ge ' letfy := letfx := e0 ge1 ge The remaining axioms rules concerning operational equivalence (other than that it is an equivalence relation) are: ( =.i), equivaluedness implies operational equivalence; ( =.ii), operational equivalence is preserved under the collection of garbage; ( =.iii), operational equivalence is non-trivial on abstractions; and they agree with one another on atoms and cells, ( =.iv). Operational Equivalence rules ( =).

(i) ` e0  e1 ) e0  = e1 (ii) ` e  = ?[e] provided FV(e) \ Dom(?) = ; ` e0  = e1 (iii) (The  Rule) ` x:e0  = x:e1 (iv) ` (x)  t ^ (y)  t ) (x  = y , x  y)

4.2



2 fatom?; cell?g

Contextual Axioms and Rules

Contextual assertions are a modality and as such possess a rule akin to necessitation, (C.i). Note that this is a rule of proof and not an implication. A simple counterexample to the implication can be found in x3.3. The remaining axioms concerning contextual assertions are: (C.ii), contextual assertions distribute across the equivalences, again a counterexample to the converse can be found in x3.3; (C.iii), a form of contextual assertion introduction involving equivaluedness (the corresponding principle for operational equivalence is false, x3.3.1); (C.iv), a principle akin to conversion; and (C.v), a principle allowing for the manipulation of contexts. Contextual rules (C).

(i) ` `L[[]]

(Context Introduction)

10

(ii) (iii) (iv) (v) 4.3

` L[[e0 ' e1 ] ) L[e0] ' L[e1] ` e0  e1 ) (letfx := e0 g[ ]] , letfx := e1 g[ ]]) ` letfx := vg[ ]] , fx:=vg ` letfx := e0 gletfy := e1 g[ ]] , letfy := letfx := e0ge1 g[ ]] Logical Axioms and Rules

The propositional rules are, in addition to the usual Hilbert style presentation of modus ponens, (P.iii), and a generating set of tautologies, (P.i) a modal axiom corresponding to K and its converse, (P.ii). Propositional rules (P).

(i) `  provided  is an instance of a tautology (ii) ` L[[0 ) 1 ] , (L[[0] ) L[[1] ) `  0 `  0 ) 1 (iii) (Modus Ponens) ` 1 Similarly the quantifier axioms are all standard [10] except for (Q.iv) and (Q.v) which assert that operations other than mk and app have no allocation effect, and that mk only allocates the value it returns. Quantifier rules (Q).

` (i) ` (8x)fy:=xg (Generalization 8I) (ii) ` (8x)(0 ) 1 ) ) (0 ) (8x)1 ) (iii) ` (8x) ) fx:=vg (iv) ` (8x)letfz := #(y )g[ ]] ) letfz := #(y)g[ (8x)]] # 2 F ? fmk; appg (v) ` ((8x)letfz := mk(y)g[ (x)]] ^ letfz := mk(y)g[ (z)]]) ) letfz := #(y)g[ (8x)]] Note that the converses of these last two axioms are easily derivable.

4.4

Undefinedness Principles

The most basic principle concerning undefinedness is that two undefined terms are both equivalued and operationally indistinguishable, (U.i). The rest of the principles concern the partiality of the underlying operation. Note that in the case of the memory operations mk and set, being defined is not the same as being equivalent to a value. In the other cases this is true, although we need only express the weaker form. The stronger forms are derivable. Undefinedness rules (U).

(i) (ii) (iii) (iv) (v)

` " e0 ) (" e1 , e0 ' e1 ) ` # mk(z) ` # set(z; x) , cell?(z) ' t ` # get(x) , cell?(x) ' t , (9y)(get(x) ' y) ` # #(x) for # 2 T[ feq; brg 11

4.5

Data Operation Axioms and Rules

We treat each operation in turn. We should point out, however, that we have grouped together a collection of principles that concern when an assertion propagates into or out of a context. They may be found after this collection, (S). The principles concerning mk, other than the definedness principle above, (U.ii), are quite straightforward. ( mk.i) describes the allocation effect of a call to mk. While (mk.ii) and (mk.iii) assert that the time of allocation has no discernable effect on the resulting call. In a world with control effects e0 must be free of them for this principle to be valid [17]. mk rules (mk).

(i) ` letfx := mk(z)g[ :(x ' y) ^ cell?(x) ' t ^ get(x) ' z]] x fresh (ii) ` letfy := e0 gletfx := mk(z)ge1 ' letfx := mk(z)gletfy := e0ge1 (iii) ` letfy := e0 gletfx := mk(z)g , letfx := mk(z)gletfy := e0 g The first two contextual assertions regarding set are analogous to those of (mk.i). They describe what is returned and what is altered, what is not altered. The remaining four principles involve the commuting, cancellation, absorption, and idempotence of calls to set. For example the set absorption principle, (set.v), expresses that under certain simple conditions allocation followed by assignment may be replaced by a suitably altered allocation. set rules (set).

(i) (ii) (iii) (iv) (v) (vi)

` letfx := set(z; y)g[ get(z) ' y ^ x ' nil] ` (y ' get(z) ^ :(w ' z)) ) letfx := set(w; w0)g[ y ' get(z)]] ` :(x0 ' x2) ) seq(set(x0; x1); set(x2; x3)) ' seq(set(x2; x3); set(x0; x1)) ` seq(set(x; y0); set(x; y1 )) ' set(x; y1) ` letfz := mk(x)gseq(set(z; w); e) ' letfz := mk(w)ge ` get(x) ' y ) set(x; y) ' nil

The rules concerning eq are unproblematic. It is either true or false, ( eq.i). Note that this dichotomy will imply that a call to eq is always equivalent to a value. It is true only when its arguments are both atoms and are equivalued, (eq.ii). eq rules (eq).

(i) ` eq(x; y) ' t _ eq(x; y) ' nil (ii) ` eq(x; y) ' t , (x ' y ^ atom?(x) ' t ^ atom?(y) ' t) The recognisers are similarly simple. They are either true or false, ( .i), and hence always equivalent to values. They are the characteristic functions of disjoint, and exhaustive sets, ( .ii). And they correspond to the appropriate sets in question, ( .iii).  rules, ( 2 T) ( ). (i) ` (x) ' t _ (x) ' nil ^ 0 (ii) ` (x) ' t ,  (x) ' nil

T

 2 ?f g 0

(iii) ` atom?(v) ' t (iv) ` lambda?(v) ' t

2A provided v 2 L

provided v

12

The branching primitive is as simple as eq. If its first argument is false then it returns its third argument, (br.i). If its first argument is not false then it returns its second argument, (br.ii). These together imply that a call to br is always equivalent to a value. br rules (br).

(i) ` x ' nil ) br(x; y; z) ' z (ii) ` :(x ' nil) ) br(x; y; z) ' y 4.6

Constraint Propagation Principles

An important class of axioms are those which allow assertions to propagated into and out of assertions. Static ' rules (S).

(i) (ii) (iii) (iv)

` letfx := #(z )g[ x ' #(z )]] for # 2 F ? fmk; appg ` (z0 ' z1) ) letfx := #(y)g[ (z0 ' z1 )]] for # 2 F ` # #(y ) ) (letfx := #(y )g[ (z0 ' z1 )]] ) (z0 ' z1 )) for # 2 F ` (z ' #0(y )) ) letfx := #1(w)  g[ (z ' #0(y ))]] #0 ; #1 2 F

2 fset; appg, then #0 2 F ? fget; set; appg. (v) ` # #1(w)  ) (letfx := #1(w)  g[ (z ' #0(y ))]] ) (z ' #0(y ))) provided that if #1 2 fset; appg, then #0 2 F ? fget; set; appg. provided that if #1

As an aside we point out that (S.i) is provable when #

= set.

fget; set; appg, then the principles have simple counterexamples. 4.7 1. 2.

# 0 ; #1

2F

In (S.iv) and (S.v) if #1

2 fset; appg and #0 2

Notes and Observations The only axioms and rules concerning get are those in (S), (U), (mk) and (set). Some axioms above are new in the sense that they have replaced principles that appeared in the earlier treatments [34, 23, 37, 24]. These were pointed out to me by Jacob Frost [20]. (C.r.i) (C.r.ii)

` letfx := R[e]g , letfz := egletfx := R[z]g ` R[letfx := e0 ge1 ] ' letfx := e0 gR[e1] x not free in R

Proof (C.r.i): (1) (2) (3)

` R[e]  letfz := egR[z] ` letfx := R[e]g , letfx := letfz := egR[z]g ` letfx := R[e]g , letfz := egletfx := R[z]g

C:r:i

13

by (E.vi) by (1, C.iii) and (P) by (3, C.v) and (P).

Proof (C.r.ii):

` R[letfx := e0 ge1] ' letfy := letfx := e0 ge1 gR[y]

(1)

by (E.vi).

` R[letfx := e0 ge1] ' letfx := e0 gletfy := e1 gR[y]

(2)

from (1) using (E.vii, E.ii).

` R[letfx := e0 ge1] ' letfx := e0 gR[e1]

(3)

from (2) using (E.vi, C.i, C.ii) and (E.ii).

3.

C:r:ii

Similarly an previous quantifier principle (Q.p)

` L[[(8x)]] ) (8x)L[[]]

where x

62 FV(L) [ Traps(L)

is now derivable, again pointed out to me by Jacob Frost [20]. Proof (Q.p):

` (8x) )  ` L[[(8x) ) ]] ` L[[(8x)]] ) L[[]] ` (8x)(L[[(8x)]] ) L[[]]) ` L[[(8x)]] ) (8y)(L[[]])

(1) (2) (3) (4) (5)

by (Q.iii) from (1) using (C.i) from (2) using (P.ii) and Modus Ponens from (3) using (Q.i) from (4) using (Q.ii) and the assumption that x

62 FV(L)

Q:p 4.8

Derived Rules

Because L[[ ] is a modality akin to we do not have a deduction theorem. However one can easily establish a weak form of the deduction theorem which is useful. Theorem (Weak Deduction): 1 Assume that from ` 0 one can establish ` 1 , without using context introduction, (C.i); the  rule, ( =.iii); or generalization on any variable free in 0 . Then ` 0 ) 1. Proof (Weak Deduction): This is a very simple induction on the length of proof. A simple corollary of this is a version of reduction ad absurdum:

(` )

(Reductio Ad Absurdum)

` False ` :

is derivable if the derivation

(` )

` False

does not use context introduction, (C.i); the  rule, ( =.iii); or generalization on any variable free in . Since if this is the case then in fact using (weak deduction) we have

`  ) False: 1 We could strengthen the theorem by weakening the condition without using to without using on any formula depending on the assumption `

14

0

And consequently by definition ` :. A similar observation reduces the strong form of ( 9I)

(` 0) ` 1

(9E)

` (9y)0

y

` 1

62 FV(1 )

to the derivable form:

(9E) 4.9

`  0 ) 1 ` (9y)0 ) 1

y

62 FV(1 )

Simple Counterexamples

The following variations on the (S) principles are not valid.

(1)

fx := #(z )g[ x ' #(z )]]

let

#

2 fmk; appg

(2)  (z ' #0 (y )) ) letfx := #1(w)  g[ (z ' #0(y ))]] #1 2 fapp; setg and #0 2 fset; get; appg (3) # #1(w)  ) (letfx := #1(w)  g[ (z ' #0 (y ))]] ) (z ' #0(y ))) #1 2 fapp; setg and #0 2 fset; get; appg 5

Completeness

We say that an expression is first order, e 2 E  , iff it contains neither unapplied -expressions, nor non- applications. A formula is first order,  2 W , iff it is built up from first order expressions. The appropriate first order syntactic subclasses are defined formally by the following mutually recursive definitions: Definition (V L E  W ): V = X+ A

L = X:E

+ P

E

= V + app(L; E ) + (Fn ? fappg)(E n) W = (E  ' E ) + (W ) W ) + (letfX:= E  g[ W] ) + (8X)(W) ~ ): Definition ( 

~ , are defined as follows: The set of constraints, , and the set of complex constraints, 

 := (V  V) + (F1 ? fmkg)(V  V) ~ := (V ' V) + (F1 ? fmkg)(V ' V) + (~ ) ~ ) A simple constraint set, , is defined to be a finite subset of ,  2 P! (). A complex constraint,  ~ , is an element of ~ . We let  range over simple constraints sets, and ~ range over complex constraints. A simple constraint is said to be static if it is a subset of  ? fgetg(V). A complex constraint is said to be static if it is a boolean combination of elements from  ? fgetg(V). Note that by (S), static constraints propagate through any contextual assertion.

It would perhaps be more symetric if we defined simple constraints to be conjunctions of constraints. The reason we define them to be sets constraints is to facilitate a single definition, in particular M below. Modulo this one definition, 15

the reader may reasonably assume that  is a finite conjunction of elements from . Thus any simple constraint set is equivalent to a single complex constraint. Note that a constraint set is a finite collection of formulas of the form v0  v1 or :(v0  v1 ) or

fget; atom?; cell?; lambda?g(v0 )  v1 : Negations of the latter are not needed since :(#(v0)  v1) can be rewritten as f#(v0)  z; :(z  v1 )g for z fresh.

We sometimes abuse notation and identify  with the conjuction of its members, hence treating a simple constraint set as a special type of complex constraint. Definition (Cells()):

Cells() is the subset of FV() defined by

Cells() = fx 2 FV()  j= cell?(x)  tg: If x 2 Cells(), then x must be interpreted as a cell. To express the constraints implicit in a memory context define for any  the extension of  by ? relative to a given set of variables X to be ?X : Definition (?X):

?X cells contents distinct 5.1

= = = =

? we

If X 2 P! (X? Dom(?)) and FV() \ Dom(?) = ;, then we define ?X as follows

 [ cells [ contents [ distinct fcell?(z)  t z 2 Dom(?)g fget(z)  ?(z) z 2 Dom(?)g f:(z  y) y 2 FV() [ X [ (Dom(?) ? fz g); z 2 Dom(?)g:

The First Completeness Theorem

We begin by proving a quantifier free version of the main theorem. The full version is then a simple generalization. Theorem (Completeness – I): such that

If 

2 W is first order and is quantifier free, then there is a complex constraint ~

` ~ ,  Note that by using propositional calculus together with (P.ii) (i.e. the principle

` L[[0 ) 1] , (L[[0] ) L[[1] )) it suffices to demonstrate the theorem when  is of the form

|L1[ L2{z[ : : :Ln}[ e0 ' e1 ] : : :]]] n0

For this reason we define

L = f  g + letfX:= E  gL and let L range over L . The proof of the completeness theorem involves the symbolic evaluation of arbitrary formulas and expressions, with respect to a suitable set of constraints, to a canonical form. The symbolic evaluation of an expression, with respect to a set of constraints , requires keeping track of three things: the newly allocated memory; the modifications to the original memory (described by ); and the remaining computation. The remainder of a computation is simply an expression. The newly allocated memory is simply a memory context. The modifications to the original memory are represented

16

by another special kind of context called a modification, M. We begin by defining relative to a fixed constraint set  a  symbolic reduction relation 7! . It is defined in such a way that:

(L 0[ 0] 7!  L 1 [ 1] )

Contexts:

implies

`  ) (L 0[ 0] , L 1 [ 1] )

and

Expressions:

(e0 7!  e1 )

implies

`  ) e 0  e1 :

The definition requires the notion of a modification and the corresponding decomposition of contexts and expressions. The effects that the evaluation of an expression has on the original memory, described by constraints, are represented by contexts called modifications. They are simply sequences of assignments to variables that are not in the domain of the memory context, but are assumed to be cells. Definition (Modifications):

(

A modification, M, is a context of the form

(z1 ; v1 ); : : :; set(zn ; vn ); )

seq set

where zi

= zj implies i = j . i = 1; : : :; n. 5.2

We define

Dom(M) = fz1 ; : : :; zn g and (in analogy with ?(x)) M(zi ) = vi for

 -Reduction



In analogy to the semantic reduction relations we define 7! , and 7! . In order to ensure that definitions are meaningful we introduce the notion of coherence. Roughly a constraint and a pair of memory and modification contexts are coherent (written Coh(; ?; M)) if Dom(?) \ FV() = ;, modifications in M are to elements of Cells(),  decides equality on Cells(), distinct elements of Dom(M) are provably distinct in , and  contains at most one get assertion for any z in Cells(). (The last condition is a technicality to make various definitions and proofs simpler.) Definition (Coherence): If ? is a memory context and M is a modification as above then we say (; ?; M) is coherent, written Coh(; ?; M), if the following five conditions hold: (1) Dom(?) \ FV() = ; (2) Dom(M)  Cells() (3) If x0; x1 2 Dom(M) are distinct, then  j= :(x0  x1). (4) If x0; x1 2 Cells(), then  j= (x0  x1) or  j= :(x0  x1). (5) If x 2 Cells(), then there is at most one formula (get(z)  v) 2  with  j= (z  x), and if (get(z)  v) 2 , then x 2 Cells(). We write Coh(; M) for Coh(; ?; M) when Dom(?) is empty, when Dom(M) is empty we write Coh(; ?) for Coh(; ?; M), and when Dom(?) and Dom(M) are both empty we write Coh() for Coh(; ?; M). One use of the notion of coherence is to ensure the simplicity of the following definition of M . If a modification, M, and a constraint set, , are coherent, then the modification of  implicit in M is made explicit in M. To construct M from  we first remove the set of all assertions in  concerning contents of cells that are mutated by M. The set removed is referred to as forget and is well defined by virtue of coherence. Then we add to  ? forget the set of assertions, assign concerning the cells updated by M. Definition (M):

For Coh(; M) we define M as follows

M = ( ? forget) [ assign assign = fget(z)  v M(z) = v; z 2 Dom(M)g forget = f(get(x)  v) 2  (9z 2 Dom(M))( j= x  z)g

17

Definition (Mfz := mk(v)g ): Suppose that M is a modification, Coh(; M) and z 2 Cells(). Then Mfz mk(v)g is defined to be the modification M0 with Dom(M0 ) = Dom(M) [ fz g, and for z 0 2 Dom(M0)



0 M0(z 0 ) = M(z )

if  if 

v

j= :(z  z 0 ) j= (z  z 0 )



Definition (e0 7! e1 ): Assume that Coh(; ?; M) and that expressions is the reflexive transitive closure of 7! given by: ( v ) ( ) (eq)

(br) (mk) (get) (set)

:=

0 = (? )M .

Then the reduction relation

7   on !

?[M[R[app(x:e; v)]]] 7! ?[M[R[efx:=vg]]]  t]]] if 0 j= (v)  t ?[M[R[(v)]]] 7! ?[M[R[ provided  2 T ?[M[R[nil]]] if 0 j= (v)  nil  t]]] if 0 j= t (v0 ; v1), ?[M[R[eq(v0 ; v1)]]] 7! ?[M[R[ ?[M[R[nil]]] if 0 j= : t (v0; v1 ) t (v0 ; v1 ) := v0  v1 ^ atom?(v0 )  t ^ atom?(v1 )  t  ?[M[R[v1]]] if 0 j= :(v0  nil) ?[M[R[br(v0 ; v1; v2)]]] 7! ?[M[R[v 2]]] if 0 j= v0  nil ?[M[R[mk(v)]]] 7! ?fz := mk(v)g[M[R[z]]] z fresh ?[M[R[get(z)]]] 7! ?[M[R[v]]] if 0 j= get(z )  v  ?fz := mk(v)g[M[R[nil]]] if z 2 Dom(?) ?[M[R[set(z; v)]]] 7! ?[M fz := mk(v)g [R[nil]]] if  j= cell?(z)  t 



Definition (L 0 [ 0] 7! L 1[ 1] ): Assume that Coh(; ?; M). Then the reduction relation 7! on formulas is the reflexive transitive closure of 7! given by: (val) (red)

?[M[letfx := vg]][[]] 7! ?[M][[fx:=vg ] ?[M[letfx := egL ]][[]] 7! ?1[M1[letfx := e1gL ]][[]] provided ?[M[e]] 7! ?1 [M1 [e1 ]]

Lemma (Coherence): Coherence is preserved by syntactic reduction. The Context Modification Introduction lemma, (CMI), generalizes the contextual assertions concerning mk and set to arbitrary memory–modification contexts pairs. Lemma (CMI):

If Coh(; ?; M) and X

= FV(?[M[R]]) [ FV() then

`  ) ?[M[R]][[(?X )M ] : Proof (CMI):

Let

cells = fcell?(z)  t z 2 Dom(?)g contents = fget(z)  ?(z) z 2 Dom(?)g distinct = f:(z  y) y 2 X [ (Dom(?) ? fz g); z 2 Dom(?)g: 18

Suppose without loss of generality that:

? = letfz1 := mk(nil)g : : : letfzn := mk(nil)g seq(set(z1 ; v1); : : :; set(zn ; vn); ) M = seq(set(x1; v10 ); : : :; set(xm ; vm0 ); ) Then

`  ) letfz1 := mk(nil)g : : : letfzn := mk(nil)g[ ]] by (S) and propositional logic (P)

`  ) letfz1 := mk(nil)g : : : letfzn := mk(nil)g[ cells [ distinct ] by (S), (mk.i) and propositional logic (P)

`  [ cells [ distinct ) seq(set(z1 ; v1 ); .. .

(zn ; vn ); )[[ [ cells [ distinct [ contents ]

set

by (S), (set.ii), (set.i) and propositional logic (P)

Thus by the above and (P.cut)

`  ) ?[[?X]

Now by coherence we may split  into two disjoint sets 0 and forget so that (a.) for any (v  get(w)) 2 0 we have that 0 j= :(x  w) for every x 2 Dom(M) = fx1 ; : : :; xm g. (b.) forget contains only those statements of the form (v  get(w)) such that there is an x 2 Dom(M) = fx1; : : :; xm g such that 0 j= x  w. Thus

` 0 [ cells [ distinct ) seq(set(x1 ; v10 ); : : :; set(xm ; vm0 ); )[[0 [ cells [ distinct ] by (S), (set.ii), (set.i), (a.) and propositional logic (P)

` 0

) seq(set(x1; v10 ); : : :; set(xm ; vm0 ); )[[fget(xi)  vi i = 1; : : :; mg] by (S), (set.ii), (set.i), and propositional logic (P)

Thus by the above, (P.cut) and (C.rdx)

`  ) ?[M[R]][[(?X)M ] CMI

A simple but useful corollary of (CMI) is the following: Corollary (cmi): If

Coh(; ?; M);

and

` (? )M ) " e;

then

`  ) " ?[M[R[e]]]:

Proof (cmi): (1) (2) (3) (4) (5) (6)

`  ) ?[M[R]][[(?X )M ] ` (?)M ) " e `  ) ?[M[R]][[" e]] `  ) ?[M[R]][[seq(e; False)]] `  ) seq(?[M[R[e]]]; [ False] ) `  ) " ?[M[R[e]]]

by (CMI). by assumption. by the above two facts and (P.cut). by definition. by repeated application of (C.r) by definition.

19

cmi

Before we state the key lemmas, we require one last set of definitions. Syntactic reduction is defined so that if  contains enough information concerning the nature of the free variables of e, then

e 7!  ?[M[e0]];

and either e0

= v or else e0 corresponds to a stuck state, one that cannot reduce due to simple type mismatches.

Definition (-stuck state): An expression e is said to be -stuck state if e can be written as ?[M[R[e0]]] for some ?, M, and e0 , such that e0 2 fget(v); set(v; v0 )g; and (? )M j= cell?(v)  nil.  An expression e is said to reduce to a -stuck state if e 7! e0, and e0 is a -stuck state. Similarly a formula L [ ]] is said to reduce to a -stuck state if

L [ ]] 7!  ?[M[letfx := R[e0]g]][[0]

Coh(; ?; M), and ?[M[R[e0]]] is a -stuck state.

In order to formalize the notion of a constraint set  containing enough information, we make the following definitions. A accessor chain of length n is a reduction context of the form

#1(#2(: : :#n () : : :)) where #i 2 fgetg Note that an accessor chain of length 0 is just . Finally we define the notion of n-completeness for constraint sets relative to a finite set of variables and atoms, [ x; A]. The idea is that such a constraint set contains sufficient information to completely determine the evaluation of any expression of size less than n built from the given variables and atoms. Definition (n-Complete w.r.t. [ x; A]):  is n-complete w.r.t.  n, and y; y0 2 x, if  j= [y]  v and  j= 0 [y0 ]  v0 , then (1) (2) (3) (4)

 j= (v)  t or  j= (v)  nil  2T  j= v  or  j= :(v  ) 2 A [ ft; nil; v0g  j= cell?(v)  t implies (9v0 2 V)( j= get(v)  v0 )  j= cell?(v)  nil implies :(9v0 2 V)( j= get(v)  v0 )

Definition (Atoms(Z)):

5.3

[x; A] if for every ; 0 , accessor chains of length

If Z

 E, then Atoms(Z) is the set of atoms occurring in Z .

The Main Lemmas

The following five lemmas enable a straightforward proof of the completeness theorem. Lemmas 0., 1., 3., and 4. hold for the full language, while Lemma 2. holds only for those expressions which are first order. Lemma (0):

~0 j= ~1

If  ~0 and ~1 are complex constraints, then iff

` ~0 ) ~1:

Lemma (1):  (i) If e 7! e0 , then `  ) e  e0 .   (ii) If L [ ]] 7! L 0[ 0] , then `  Lemma (2):

) (L [ ]] , L 0[ 0] ).

Assume e, L [ ]] are first order, FV(e; L )  X, Atoms(; e; L)  A and that m 2 N. 20

(i) If  is (r(e) + m)-complete w.r.t. [X; A] and Coh(), then either e reduces to a -stuck state, or else there exists  a memory context ?, a modification M, and a v such that e 7! ?[M[v]], Coh(; ?; M) and (?)M is m-complete w.r.t. [X [ Dom(?); A [ Atoms(v)]. (ii) If  is (r(L )+m)-complete w.r.t. [X; A] and Coh(), then either L [ ]] reduces to a -stuck state, or else there  exists a memory context ?, a modification M and a substitution  such that L [ ]] 7! ?[M][[] , Coh(; ?; M) and (?)M is m-complete w.r.t. [X [ Dom(?); A [ Atoms(Rng())].

, A 2 P! (A ), and n 2 N there exists N Lemma (3): For any consistent ; x figi