A COMBINATORY LOGIC MODEL
OF
PROGRAMMING LANGUAGES
by
S. Kamal Abdali
A thesis submitted in partial fulfillment of the
requirements for the degree of
DOCTOR OF PHILOSOPHY
(Computer Sciences)
at the
UNIVERSITY OF WISCONSIN
1974
ACKNOWLEDGMENT
I would like to thank Professor George Petznick for the
advice, guidance, and constructive criticism I received from
him during the research for this thesis.
I am also grateful
to Professors Donald Fitzwater, Lawrence Landweber, and
Edward Moore for being on my examination committee and
offering valuable suggestions.
My special appreciation goes
to Professor Tad Pinkerton for helping me during some
desperate moments.
I also acknowledge my indebtedness to the Courant
Institute, where most of this work was done, for a
stimulating research environment, and to the AEC Computing
Center, for the computing facilities used in the
experimental verification of parts of this model.
ii
A COMBINATORY LOGIC MODEL OF PROGRAMMING LANGUAGES
S. Kamal Abdali
Under the supervision of Assistant Professor George W.
Petznick
A simple correspondence is presented between a large
subset of the ALGOL 60 language and the combinatory logic.
With the aid of this correspondence, a program can be
translated into a single combinatory object.
The
combinatory object representing a program is specified, in
general, by means of a system of reduction relations among
the representations of the program constituents.
This
object denotes, in terms of the combinatory logic, the
function that the program is intended to compute.
The model has been derived by using intuitive,
functional interpretations of the constructs of programming
languages, completely avoiding the notions of machine
command and address.
In particular, the concepts of program
variable, assignment, and procedure have been accounted for
in terms of the concepts of mathematical variable,
substitution, and function, respectively.
High-level programming language features are represented
in the combinatory logic directly, not in terms of the
representations of machine-level operations.
Input-output is
treated in such a manner that when the representation of a
iii
program is applied to the representations of the input items,
the resulting combination reduces to a tuple of the
representations of the output items.
The applicability of the model to the problems of
proving program equivalence and correctness is illustrated
by means of examples.
Approved by George W. Petznick
(signed)
iv
CONTENTS
Page
Chapter 1.
Introduction
1
1.1
Preliminary Remarks
1
1.2
Background
5
Chapter 2.
The Combinatory Logic
11
2.1
Morphology and Transformation Rules
11
2.2
Functional Abstraction
18
2.3
The Lambda-Calculus
31
2.4
Additional Obs
38
Basic Programming Features
57
3.1
An Overview
57
3.2
Constants, Operations, Relations
60
3.3
Variables
64
3.4
Expressions
71
3.5
Assignments
76
3.6
Compound Statements
82
3.7
Blocks
86
3.8
Input-Output
91
3.9
Programs
94
3.10
Conditional Statements
97
3.11
Arrays
99
Chapter 3.
v
Chapter 4.
Iteration and Jump Statements
105
4.1
Recursive Specification of Obs
105
4.2
Iteration Statements
111
4.3
Jump Statements
116
Procedures
123
5.1
F-procedures
123
5.2
Call-by-name, Side-effects
126
5.3
Integer Parameters
128
5.4
Label Parameters
145
Conclusion
147
Chapter 5.
Chapter 6.
References
150
vi
CHAPTER 1
INTRODUCTION
1.1
Preliminary Remarks
Before we can model programming languages, we have to be
definite about what is to be regarded as the meaning of a
program.
In our view, the meaning of a program is a function.
A program prescribes the computational steps which produce the
value of some function corresponding to a given value of the
function argument.
It is precisely the function intended to be
computed by a program that we take to be the meaning of the
program.
Consequently, in order to model programming languages
mathematically, we seek to formulate rules for deriving the
mathematical definitions of functions from the computational
representations of functions provided in the form of programs.
The problem of obtaining the mathematical definition of a
function from the text of a program computing that function is
quite non-trivial.
To describe computations, programming
languages make use of a number of concepts that are not present
in the customary mathematical notations for representing
functions.
Central to the present-day programming languages --
and the main source of difference between the diction of
mathematics and that of programming languages -- is the notion
of a computer memory.
program variable.
Consider, for example, the concept of
Whereas a mathematical variable denotes a
1
2
value, a program variable denotes an address in the computer
memory.
Or, compare the notion of substitution used in the
functional calculi with the notion of assignment used in
programming languages.
Again, whereas the former is concerned
with values, the latter is concerned with addresses.
Similarly, the notion of function used in mathematics is
radically different from the notion of procedure used in
programming languages; the evaluation of functions requires
straightforward substitution of the argument values in the
functional definitions, while the execution of procedures
requires rather elaborate manipulation of information involving
a complex of memory locations.
For a long time now, two types of constituents have been
distinguished in programming languages [17] -- the descriptive
elements, such as expressions and functions, and the imperative
elements, such as assignments, instruction sequencing, and
jumps.
In addition, high-level programming languages also
contain declarative elements, such as type, array, and block
declarations, and name and value specifications for procedure
parameters.
Although the descriptive and the declarative
elements are often lumped together [17,36], we feel that these
two classes should be recognized as quite distinct; while the
purpose of the former is mainly to designate values, the
purpose of the latter is to remove ambiguities and to impose
structure on program and data.
Indeed, the declarative
features often serve to interconnect the descriptive and the
3
imperative components of a program.
The imperative constituents have their origin in machine
languages from which the present-day high-level programming
languages have evolved.
The descriptive constituents have been
introduced for ease and conciseness of notation, as well as for
making the programs resemble more closely the functions they
compute.
The addition of such constituents to programming
languages thus represents a step away from the machine and
towards mathematics.
The declarative constituents have been
added for, ostensibly, improving the clarity and transparency
of programs.
But in actual fact, by introducing sophisticated
address-related concepts, most declarative features represent a
step back to the machine, and their presence often makes the
recognition and extraction of the functional meaning of a
program more difficult than would be in their absence.
The descriptive features of programming languages lend
themselves to mathematical interpretation in quite a natural
manner.
It is the presence of imperative and declarative
features that obscures the functional meaning of a program.
And the essence of that obscurity is in the dependence of these
features upon the concept of computer memory.
Thus, the key to the extraction of functional meaning of
programs lies in modelling programming constructs without using
the idea of memory address.
This is the task that we undertake
to do in the present dissertation.
In particular, we seek to
explain program variables in terms of mathematical variables,
4
the operation of assignment in terms of substitution, and
procedures, programs, and, in general, all program statements
in terms of functions.
To express programming constructs, we make use of the
notation and terminology of ALGOL 60 [27], with a few,
explicitly stated, extensions.
As the mathematical theory for
modelling the programming constructs, we make use of the
combinatory logic [8,9,33,34], originated by Schönfinkel and
developed principally by Curry.
A remarkable feature of this
theory is the absence of variables.
Nevertheless, functions
can be represented by the objects of this theory in a natural
manner.
Thus, by using the combinatory interpretation of
programming languages, we seek to eliminate variables
altogether, program-related or mathematical.
5
1.2
Background
A number of combinatory logic (or, related, lambda-
calculus) models of programming languages have appeared in the
literature.
The most well known of these are due to Landin.
In [16], Landin uses the lambda-calculus to model the semantics
of expression evaluation in programming languages.
He also
prescribes the semantics of the lambda-calculus itself by means
of an interpreter, the SECD machine, to evaluate lambdaexpressions.
But in extending his model to include the
imperative features of ALGOL 60, he elects [17] to supplement
the lambda-calculus and its evaluator with such concepts as the
assigner, the jump operator, and sharing.
Due to their
pioneering nature and their thoroughness of analysis, Landin’s
papers have greatly influenced the subsequent work on
programming semantics.
But they have also been instrumental in
creating the rather unfair impression that the pure lambdacalculus is not an appropriate medium for representing the
imperative notions of programming languages (see for example
[2]).
The direct superimposition of imperative concepts on the
lambda-calculus seems to us unsuitable on several grounds.
First of all, there is no guarantee of the preservation of
consistency in the augmented calculus.
Then, by defining the
new calculus in terms of the sequentially operating “sharing
machine”, one throws away the most important property of the
lambda-calculus, the Church-Rosser property [9], which implies
6
that the values of lambda-expressions are independent of their
evaluators.
Finally, the resulting model of programming
languages forces one to identify a program with its execution
trace; it fails in capturing the abstract function underlying
the computation expressed in the program.
Stratchey [36] also uses the lambda-calculus to model
programming language semantics.
Unlike Landin, he under-takes
to represent the imperative as well as the declarative and
descriptive notions of programming languages in terms of the
descriptive concepts of the lambda-calculus.
To account for
the notion of assignment, however, he postulates a number of
primitives to represent the generalized concepts of address and
the related memory fetch and store operations.
Thus, by not
going as far as to eliminate program variables in favor of
mathematical variables, Stratchey’s model is again
computational rather than functional.
As Burstall points out
in describing another lambda-calculus model [5] of programming,
it is unnecessary to introduce any assignment-related concepts
as primitives.
Indeed, Burstall shows how assignments can be
naturally modelled by the lambda-calculus operation of
substitution.
We remark that our approach is closest to
Burstall’s in spirit, though we adopt a different method of
representing assignments.
Orgass and Fitch [28] have developed a theory of
programming languages in a system of the combinatory logic.
They represent the computer memory as an n-tuple and the
7
machine state transitions caused by the execution of
instructions as functions on n-tuples.
Their representation of
programming languages is in rather general terms, and it is not
clear how it can be used to obtain the representation of
specific programs.
The main drawback in their model seems to
be the lack of treatment of declarative features, so that their
discussion of programming languages is applicable, for the most
part, to machine-level languages only.
A number of researchers have used the combinatory logic or
the lambda-calculus to model only some important programming
constructs rather than full-fledged programming languages.
In
[26], Morris explores the concepts of recursion and types in
the lambda-calculus, but his work is also relevant to these
concepts as they occur in programs.
Ledgard [18] describes a
model of type checking in which lambda-expressions are used to
abstract out the type relations within a program.
In addition,
we mention the work of Böhm [4], Petznick [29], Milner [25] and
Henderson [11], who obtain the representations of various
elementary programming constructs and schematic programs in the
combinatory logic or the lambda-calculus.
The semantics of the lambda-calculus itself has attracted
considerable attention.
We have already mentioned Morris’
results on recursion and types [26] and Landin’s SECD machine
[16] for evaluating lambda-expressions.
The formal
specification of several lambda-calculus interpreters
(originally due to Wegner [37]), and proofs of their mutual
8
equivalence have been given by McGowan [24].
The Wegner-
McGowan and Landin machines employ the so-called “call-byvalue” strategy of evaluating the right component of an
application before the left one.
Consequently, none of these
machines is a true normal-form reducer for lambda-expressions.
A computer to reduce the objects of the combinatory calculus to
their normal forms has been designed and proved correct by
Petznick [29].
This computer consists of stack-structured
control registers and tree-structured memory, permits shared
memory representations of equiform objects, and has provisions
for incremental programming and multiple processing.
Reynolds
[31] defines and interrelates a number of interpreters for the
lambda-calculus and for its various extensions with programming
language features.
Knuth [15] approaches the semantics of the lambdacalculus from the viewpoint of his general theory of the
semantics of context-free languages, in which the meanings of
sentences are built up, in the course of sentence generation,
from the attributes associated with non-terminal symbols.
Finally, the most abstract and incisive work on the semantics
of the lambda-calculus has been done by Scott (e.g., [35]) as
part of a very general theory of computation.
Concerned with
an abstract or functional explanation rather than with a
computational explanation, Scott represents a lambdaexpression as the limit of a certain sequence of constructions
on complete lattices.
His theory succeeds in providing very
9
convincing answers to the problems related to recursion and
self-application in the lambda-calculus.
Combinatory models constitute but a minute fraction of the
total work that has been done so far on the semantics of
programming languages.
models.
We mention just a few of the other
In [10], Floyd suggests the method of semantic
definition of programming language statements by means of pairs
of conditions that hold just before and after the statement
execution.
Apparently, little use has been made of Floyd’s
method in the definition of programming languages.
But his
idea of representing the effect of execution of program
statements by assertions has had diverse and far-reaching
consequences.
(For example, it serves as the basis of most
program proving schemes [20]).
Of all the methods of defining
programming languages, the most elaborate and the most
extensively applied is the “Vienna Method” [19,21] -- so called
because it was developed at the IBM Vienna Laboratory for the
semantic specification of the PL/l language.
In this method,
programming constructs are represented in terms of the (nondeterministic) state transitions of a machine; it thus
constitutes a computational, rather than a functional, approach
to semantics.
Among the purely functional semantic models of programming
languages based on theories other than the combinatory logic,
the most notable are: Burstall’s [6] representation of programs
by combining the Floyd-type assertions associated with the
10
programs into the formulas of first-order predicate calculus;
and Manna and Vuillemin’s [22] Scott-theoretical interpretation
of programming constructs as minimal fixed points of “recursive
programs”.
To conclude, we mention the axiomatic approach to
programming semantics, which is different from both functional
and computational approaches.
It consists in devising the
systems of axioms and inference rules which apply directly to
programming language constructs, and in which the properties of
programs may be derivable as theorems.
This approach obviates
the circuitousness involved in deriving the same properties when
one uses a “programming model” (in which case, one first
represents programs as the objects of some mathematical theory,
and then works with these representations to derive the
properties).
Igarashi [13] and deBakker [2] are the first to
propose sets of axioms dealing with elementary programming
constructs; their systems are, however, rather complex.
A very
simple and elegant axiom system (in which Floyd’s ideas again
find a new expression) has recently been presented by Hoare [12].
CHAPTER 2
THE COMBINATORY LOGIC
This chapter summarizes the properties of the combinatory
logic [8,9,33,34] which will be utilized later in the modelling
of programming languages.
The discussion is in terms of a
particular system SK consisting of only two primitive objects
(S and K), a primitive operation (combination) to form new
objects from given ones, and two primitive relations (S- and Kcontractions) between objects.
2.1
Morphology and Transformation Rules
The alphabet for SK consists of the symbols “S”, “K”, “(”,
and “)”.
As there is no possibility of confusion, we let “S”
and “K” also denote the words consisting solely of S and K,
respectively.
If a and b denote words over the alphabet, then
we denote by “(ab)” the word obtained by concatenating the
symbol “(”, the word a, the word b, and the symbol “)”.
Of all
the words over the SK alphabet, we distinguish certain words by
means of the
(1-1) Definition.
The (combinatory) obs are formed according
to the following rules:
(1)
S and K are obs.
(2)
If a and b are obs, then (ab) is an ob.
11
12
(3)
The only obs are those specified by (1) and (2).
S and K are primitive obs; any other ob, which is
necessarily of the form (ab), is a composite ob.
The composite
ob (ab) is the application of a to b, or the combination of a
and b, the obs a and b being its left and right immediate
components, respectively.
It follows that the immediate
components of an ob are uniquely determined and are nonoverlapping.
A component of an ob is either the ob itself or a
component of an immediate component of the ob.
A proper
component of an ob is a component which is not the ob itself.
The length of an ob is the number of symbols
Example.
S
and
K
in it.
The application of the ob ((KS)((SS)K)) to K is the
composite ob (((KS)((SS)K))K) of length 6, some of whose proper
components are K, S, (KS), and ((SS)K).
The same ob S has
three different occurrences as components of the above ob; all
these occurrences are to be regarded as different components.
We use the notation a ≡ b to indicate that the obs a and b
are equiform, that is, spelt the same over the SK alphabet.
We
also use this notation for introducing a as a new name for the
ob b.
We may abbreviate obs by omitting parentheses under the
convention that any omitted parentheses are to be re-inserted
by association to the left.
For example, ((SS)(SK)) maybe
abbreviated to (SS)(SK) or SS (SK).
We now state a number of rules for transforming obs.
13
(1-2) Definition.
(1)
For all obs a, b, and c:
The ob Sabc S-contracts to the ob ac(bc); in symbols,
Sabc →S ac(bc).
(2)
The ob Kab K-contracts to the ob a; in symbols,
Kab →K a.
If a →S b, then a and b are called, respectively, the S-redex
and S-contractum corresponding to each other.
K-contractum are defined analogously.
K-redex and
A redex is either an
S-redex or a K-redex.
Let an ob b be obtained from an ob a by replacing a
component c of a by an ob d.
If it is the case that c →S d or
c →K d, then a immediately reduces to b (in symbols, a →im b).
For example, K(SKSa)Sb →im SKSab, and also K(SKSa)Sb →im
K(Ka(Sa))Sb, depending on the redex selected for contraction.
(1-3) Definition.
An ob a is irreducible or in normal form if
there is no ob b such that a →im b.
Thus, no component of an irreducible ob may be a redex.
Some examples of irreducible obs are S, K, KS, SKK, and
SS(S(SSK)K).
(1-4) Definition.
An ob a reduces to an ob b, denoted a → b,
if there exist obs a0, a1,..., an, for some n > 0, such that
(1)
a ≡ a0 ,
(2)
b ≡ an ,
14
(3)
Example.
ai →im ai+1 , for 0 ≤ i < n .
SKSKSKabc → ac(bc), since
SKSKSKabc →im KK(SK)SKabc →im KSKabc →im Sabc →im ac(bc).
If a →S b, then we also say that b S-expands to a, and
write b ←S a.
K-expansion
In a similar manner, we define
(←K),
immediate
expansion
(←im),
and
expansion
(←).
(1-5) Definition.
An ob a is interconvertible with an ob b,
denoted a ↔ b, if there exist obs a0,a1,...,an, for some
n > 0, such that
(1)
a ≡ a0 ,
(2)
b ≡ an ,
(3)
ai →im ai+1 or ai ←im ai+1 , for 0 ≤ i < n.
Example.
SKKa ↔ SSSSKa, since SKKa →im Ka(Ka) →im a
←im Ka(SSKa) ←im SK(SSK)a ←im SS(SS)Ka ←im SSSSKa.
Reduction
(→) and interconvertibility (↔)
are related
by the well-known
(1-7)
Theorem (Church-Rosser) [9].
If a ↔ b, then there
exists an ob c such that a → c and b → c.
(1-8)
Corollary.
If the obs a and b are irreducible,
then a ↔ b if and only if a ≡ b.
(1-9) Definition.
A normal form of an ob a is an irreducible
ob b, if one exists, such that
a ↔ b.
An ob is normal
15
if it has a normal form.
From Theorem 1-7 and Corollary 1-8, it immediately
follows that:
(1-10) Theorem.
unique.
If an ob is normal, then its normal form is
Moreover, if b is the normal form of a, then a → b.
That is, it is possible to discover the normal form of a
normal ob by a sequence of contractions alone, starting from
the given ob.
Of course, there are obs that are not normal.
An example of such an ob is (aaa), where a ≡ SSK.
It is easily
seen that all possible reductions of the ob (aaa) either keep
producing longer and longer obs or eventually lead to (aaa)
again, so that they will continue indefinitely without ever
reaching an irreducible form.
Moreover, there are obs that are
normal but for which not every reduction terminates in a normal
form.
This is illustrated by the ob KS(aaa), with a defined as
above; its normal form S cannot be reached as long as
reductions are carried out only inside the component (aaa).
Fortunately, there exists a deterministic reduction procedure
such that, when applied to normal obs, it always arrives at
their normal forms in a finite number of steps.
It is as
follows:
(1-11) Standard Order Reduction Algorithm (Church-Rosser).
[9)
To obtain the normal form of a normal ob, start with the ob and
successively apply contractions of the leftmost redex, until no
further reduction is possible.
A modification of the above scheme is used in Petznick’s
16
combinatory computer [29], a hypothetical machine for reducing
obs to normal form.
Obs may be so represented in the memory of
this machine that all equiform components of an ob may have but
one internal representation.
The reduction takes place by
contracting the leftmost redex; but as a consequence of shared
representations, several equiform redexes may be contracted
simultaneously.
On account of Definition 1-9 and Theorem 1-10, it seems
reasonable to regard the normal form of an ob as the “value” of
the ob, and the process of normal form reduction as
“evaluation”.
Consequently, we may regard mutually
interconvertible normal obs as “equal” since they have the same
value.
This view of value and equality is similar to the one
taken in other calculi.
For example, among the equal
arithmetic expressions 2x2+3x4, 4+12, and 16, the last one is
distinguished in being “irreducible” by the rules of
arithmetic, and thus it is regarded as the value of the three
expressions.
For obs as well as for arithmetic expressions, it
so happens that the value is obtainable by a sequence of
reductions only, and it is unique despite the possible
nondeterminism involved in the order of reductions.
But unlike
the case for arithmetical expressions, there is no algorithm to
decide whether or not two given obs have the same value (i.e.,
are interconvertible).
The notion of interconvertibility is generalized in the
17
following
(1-12) Definition.
An ob a is n-interconvertible to an
ob b, in symbols a ↔n b if for all obs c1,...,cn ,
acl...cn ↔ bc1...cn
Clearly, a ↔n b implies a ↔m b for all m > n; but
the converse does not hold.
For example, we have SKS ↔1 SKK,
since SKSc → c ← SKKC for all c.
Yet SKS ¬↔0 SKK (i.e.,
SKS ¬↔ SKK) by Corollary 1-8, as the two obs are irreducible
but not equiform.
Indeed, it can easily be shown that for a
given normal ob a and an integer n ≥ 1, there exist infinitely
many obs b with distinct normal forms such that a ↔n b but,
for all m < n, a ¬↔m b.
18
2.2
Functional Abstraction
Our interest in SK derives from the fact that we can
represent programming language constructs (e.g., expressions,
statements, programs) by obs, and the processes required in the
execution of programs (e.g., substitution, expression
evaluation, procedure application) by the reduction operation.
Such a representation is possible because
1. Programming constructs can be regarded intuitively as
functions (in a special sense of the word, explained
below), and
2. Functions can be represented by obs.
This section will describe how to represent functions as obs.
We will assume that a function F is defined by means of a
functional equation of the form
F(x1,...,xn) = E
in which E is an expression that may contain constants,
variables, and already defined functions.
The variables
x1,...,xn are called the formal arguments of the function F.
To obtain the value of this function for a list of expressions
given as actual arguments, the actual arguments are substituted
in place of the corresponding formal arguments, and the
resulting expression is evaluated.
Confined for the moment to the functions of one argument
only, our basic approach to the SK representation of functions
may be stated as follows: Let F be a given set of
19
one-argument functions to be represented, and let A be the
union of the domains and ranges of the given functions.
Then
we choose obs to represent the members of F and A so as to
satisfy the following condition.
For all F in F and a,b in A,
and their respective SK representations F, a, b, if F(a) = b,
then (F a) → b.
The above representation applies as such to one-argument
functions only.
But a basic idea of the combinatory calculus,
due to Schönfinkel [34], is to regard even the functions of
several arguments as just one-argument functions.
This becomes
possible if the domains and ranges of one-argument functions
are permitted to contain one-argument functions themselves.
To
see how this idea works, suppose F is a function of two
arguments, and let Gx (for a given x) and H be one-argument
functions such that
Gx(y) = F(x,y)
,
H(x)
.
= Gx
Then for any arguments a and b, we have
F(a,b) = Ga(b) = [H(a)](b)
Now F is identified with the one-argument function H, and,
consequently, F(a,b) with [H(a)](b).
Hence, designating the
representative obs by underlining the names of the represented
functions or constants, we may choose F = H, thereby
20
representing
F(a,b)
by
((H a)b), i.e., (F a b).
(F a) represents H(a), i.e.
Note that
the function Ga . In general, if F
is a function of n arguments, then:
(F a1...am) for m < n represents the function G such
that G(xm+1,...,xn) = F(a1,...,am,xm+1,...,xn) , and
(F a1...an) represents F(a1,...,an).
With the above interpretation of functions in mind, every
expression involving only functions and constants but not
variables, written in the customary functional notation using
function application and composition, is representable in SK,
provided that its constituent functions and constants are
representable.
For example, we may represent the expression
F(G(a,b),H(J(c),d)) by the ob F(G a b)(H(J c)d), and carry out
the evaluation of the former entirely within SK by reducing the
latter.
But in order to extend our representation to the
expressions involving variables also, we require a
generalization of obs described next.
We adjoin a denumerable collection of symbols called
indeterminates to the alphabet of SK.
We do not specify these
symbols; but it will always be possible to infer from the
context whether or not a symbol is an indeterminate.
Of all
the words over the augmented SK alphabet, we characterize an ob
form to be a word that either consists of a single
indeterminate or S or K, or is of the form (e1 e2),
21
where e1 and e2 are ob forms (Cf. Definition 1-1).
All
the definitions, notational conventions, and properties related
to obs, as given in the previous section, generalize in an
obvious manner for ob forms.
Given an ob form e and an indeterminate x, we say that e
contains x, or x occurs in e, in symbols, x oc e, if x is a
component of e; x oc
/
(2-1) Definition.
e if it is not the case that x oc e.
Let e,f1,...,fn be ob forms and x1,...,xn be
distinct indeterminates.
Then the result of (simultaneous)
substitution of f1 for x1, f2 for x2 ,..., fn for xn in e,
denoted
sub [f1,x1;...;fn,xn;e]
is defined by induction on n and the structure of e as follows:
(1)
sub [f1,x1;e]
e , if x1 oc
/
≡
e,
f1 , if e ≡ x1
(sub [f1,x1;g]sub [f1,x1;h]),
otherwise, where e ≡ (gh).
(2)
sub [f1,x1;f2,x2;...;fn+1,xn+1;e]
≡ sub [f1,z; sub [f2,x2;...;fn+1,xn+1;sub [z,x1;e]]]
where z is an indeterminate which is distinct from
each of x1,...xn and which does not occur in any
of e, f1, ..., fn .
22
As a consequence of the definitions of reduction and
substitution, we have
(2-2) Lemma.
If e → e’, then
sub [f1,x1;...;fn,xn;e] → sub [f1,x1;...;fn,xn;e’].
(2-3) Definition.
Given an ob form e and indeterminates
x1,...,xn, for some n ≥ 1, an abstract of e with respect to
x1,...,xn is an ob form f such that
(1) xi oc
/ f ,
l ≤ i ≤ n ,
(2) fx1...xn → e.
Example.
For e ≡ xyz(y(xy)z), we have
e ← S(xy)(y(xy))z
← SSy(xy)z ← S(SS)xyz .
Hence, the ob S(SS) is an abstract of e with respect to x,y,z;
the ob forms S(SS)xy, SSy(xy), and S(xy)(y(xy)) are all
abstracts of e with respect to z.
Let f be an abstract of an ob form e with respect to the
indeterminates x1,...,xn.
The relations (1) and (2) of the
above definition are satisfied.
Applying Lemma 2-2 to (2), we
have for all ob forms g1,...,gn ,
sub [g1,x1;...;gn,xn;fx1...xn] → sub [g1,x1;...;gn,xn;e].
Because of (1), we can simplify the left-hand side in the
above relation and restate the relation as follows:
If f is an abstract of e with respect to x1,...,xn, then for
23
all ob forms g1,...,gn, we have
f g1...gn → sub [g1,x1;...;gn,xn;e].
(*)
Further properties of abstracts will be described later.
Earlier in this section, we have noted how the expressions
that contain already represented constants and functions can be
represented by obs.
With variables represented by
indeterminates (possibly, with the same symbolic denotation),
we can extend that scheme to represent by ob forms the
expressions that contain variables in addition to constants and
functions.
Now consider a function F defined by the functional
equation
F(x1,...,xn) = E ,
in which E is an expression containing constants, variables,
and already defined functions.
The value of F for given actual
arguments G1,...,Gn is computed by simultaneously replacing x1
with G1, ..., xn with Gn in E, and then evaluating the resulting
expression.
Let e, g1,...,gn be the ob forms representing the
expressions E, G1,...,Gn, respectively.
Then we would like to
represent the function F by an ob form (or, if possible, by an
1
ob ) f satisfying
1
It will soon become clear that if, in the functional
equation F(x1,...,xn) = E defining F, the expression E does
not involve any variable other than x1,...,xn, then F is
representable by an ob.
24
the relation
fg1...gn → sub [g1,x1;...;gn,xn;e]
Furthermore, the above relation must hold for all choices of ob
forms g1,...,gn.
But we have just seen that this is precisely
the case if f is an abstract of e with respect to x1,...,xn.
Hence, given a functional equation defining a function, any
abstract of the ob form representing the right-hand expression
in the equation with respect to the formal arguments can be
taken as the SK representation of that function.
From the property (*) of abstracts obtained earlier, it
follows that all abstracts of the same ob form with respect to
the same n indeterminates are mutually n-interconvertible
(Definition 1-12).
Also, an ob form which is n-
interconvertible to an abstract of a given ob form with respect
to n given indeterminates is itself one such abstract.
To designate an arbitrarily chosen abstract of the ob form
e with respect to the indeterminates x1,...,xn , we employ the
a
notation (A x1...xn:e).
This notation may be abbreviated by
omitting parentheses under the convention that the ob form to
the right of the colon sign extends as far to the right as is
consistent with its being well formed.
a
a
abbreviate (A xy:(A z:(x(xy)z)) to
a
For instance, we may
a
A xy:A z:x(xy)z.
We state
below some important properties of abstracts, including (*) for
completeness; some simple arguments pertaining to the
25
substitution process suffice to establish these properties:
(2-4) Theorem.
Let e, e’, g1,...,gn be ob forms and x1,...,xn
distinct indeterminates for some integer n ≥ 1.
Then:
a
(1) (A x1...xn:e) g1...gn → sub [g1,x1;...;gn,xn;e].
(2) If y1,...,yn are distinct indeterminates and
yi
oc
/
e
for 1 ≤ i ≤ n, then
a
a
A x1...xn:e ↔n A y1...yn:sub [y1,x1;...;yn,xn;e].
(3) a)
If x oc
/
e for all 1 ≤ i ≤ n, then
a
A x1...xn:ex1...xn ↔n e.
b)
Generally, for an integer
m ≤ n, if xi oc
/ e for
m ≤ i ≤ n, then
a
a
A x1...xn:exm...xm ↔n A xl...xm-l:e.
(We consider the right-hand side to be simply e when
m = 1.)
a
a
a
(4)
A x1...xi-1:A xi...xn:e ↔n A x1...xn:e, 1 ≤ i ≤ n.
(5)
If e ↔ e’, then A x1...xn:e ↔n A x1...xn:e’.
a
a
Since a function of n arguments can be represented
equally well by any one of a certain class of n-interconvertible obs, the above theorem suggests several ways of
choosing simple functional representations.
For example, to
represent the function F given by F(x1,...,xn)= E, one can take
a
the ob A x1...xn:e’, where e’ is the normal form
26
of the ob form e representing the expression E.
The properties given in Theorem 2-4 hold for all
abstracts.
We may expect that by choosing abstracts in some
specific manner, these properties could be strengthened, thus
simplifying our work with the abstracts.
That this is indeed
the case is shown by the following description of (a modified
version of) Rosser’s abstraction algorithm [33] and the
improved properties of the associated abstracts.
(2-5) Definition.
indeterminates.
Let e be an ob form and x1,...,xn be
The R-abstract of e with respect to x1,...,xn,
R
denoted (A x1...xn:e), is defined by induction on n and the
structure of e as follows:
R
(1) (A x1:e)
Ke , if x1 oc
/
e,
SKK, if e ≡ x1,
≡
f , if e ≡ (fx1) and x1 oc
/ f,
R
R
S(A x1:f)(A x1:g), otherwise, where e ≡ (fg) .
R
R
R
(2) (A x1x2...xn+1:e) ≡ (A x1: (A x2...xn+1:e)).
Again we may omit parentheses in writing R-abstracts with
the understanding that the ob form to the right of the colon
extends as far to the right as its well-formedness would
permit.
27
Example.
R
R
R
A z:xz(yz) ≡ S(A z:xz)(A z:yz) ≡ Sxy,
R
R
R
R
A yz:xz(yz) ≡ A y:A z:xz(yz) ≡ A y:Sxy ≡ Sx,
R
R
R
R
A xyz:xz(yz) ≡ A x:A yz:xz(yz) ≡ A x:Sx ≡ S,
R
R
R
A x:xy ≡ S(A x:x)(A x:y) ≡ S(SKK)(Ky) .
We obviously have x oc
/
R
A x:e, and, in general, for all
R
1 ≤ i ≤ n, xi oc
/
A x1...xn:e .
indeterminates y, if y oc
/
Note also that for all
e, then y oc
/
R
A x1...xn:e.
Thus, if
the ob form e contains no indeterminates other than xl,...,xn,
R
then A x1...xn:e is just an ob.
(2-6) Lemma.
If, for all 1 ≤ i ≤ n, xi oc
/ f and y ¬≡ xi, then
R
R
sub [f,y;A x1...xn:e] ≡ A x1...xn:sub [f,y;e] .
Proof.
Repeated application of Curry’s Corollary 4.1 [9, p.
208].
(2-7) Theorem.
Let e, e’, g1,...,gn be ob forms and xl,...,xn
distinct indeterminates for some integer n ≥ 1.
Then:
R
(1)
(A x1...xn:e)g1...gn → sub [g1,x1;...;gn,xn;e].
(2)
If y1,...,yn are distinct indeterminates and yi oc
/
for 1 ≤ i ≤ n, then
R
R
A x1...xn:e ≡ A y1...yn: sub [y1,x1;...;yn,xn;e].
(3)
a) If xi oc
/
e for all 1 ≤ i ≤ n, then
R
A x1...xn:ex1...xn ≡ e.
b) Generally, for an integer m ≤ n, if xi oc
/
e
e
28
for m ≤ i ≤ n, then
R
R
A x1...xn:exm...xn ≡ A xl...xm-l:e.
(The right-hand side is considered to be
simply e when m = 1.)
R
R
R
(4)
A x1...xi-1:A xi...xn:e ≡ A x1...xn:e, 1 ≤ i ≤ n.
(5)
If e ↔ e’, then
R
R
A x1...xn:e ↔n A x1...xn:e’ .
Proof.
For the case n = 1, parts (1) and (2) can be
verified by induction on the structure of e, and
part (3) is true by the definition of A
can be proved by induction.
. For n > 1, they
Assuming (1) true for n ≤ k, we
show it for n = k+l, as follows.
such that z oc
/
R
Choose an indeterminate z
e and, for 1 ≤ i ≤ k+l, z ¬≡ xi and z oc
/ gi .
Then:
R
(A x1x2...xk+1:e)g1g2...gk+l
R
R
≡ (A x1: (A x2...xk+1:e)) g1g2...gk+l
R
→ sub [g1,x1;( A x2...xk+1:e)] g2...gk+l ,
by the case n = 1,
R
≡ sub [g1,z;sub [z,x1;( A x2...xk+1:e)]] g2...gk+l
R
≡ sub [g1,z;( A x2...xk+1:sub [z,x1;e])] g2...gk+l ,
by Lemma 2-6,
29
R
≡ sub [g1,z;( A x2...xk+1:sub [z,x1;e])]
sub [g1,z;g2]...sub [g1,z;gk+1]
by Definition 2-1 (1), since z oc
/
g2,...,gk+1,
R
≡ sub [g1,z;(( A x2...xk+1: sub [z,x1;e]) g2,...,gk+1)]
→ sub [g1,z; sub [g2,x2;...;gk+1,xk+1; sub [z,x1;e]]] ,
by the induction hypothesis and Lemma 2-2,
≡ sub [g1,x1;g2,x2;...;gk+1,xk+1;e] ,
by Definition 2-1 (2) .
Proofs of other parts are quite simple and are omitted.
It has already been mentioned that xi oc
/
for all 1 ≤ i ≤ n.
R
A x1...xn : e
To verify that R-abstracts are indeed
abstracts (Definition 2-3), it suffices to replace gi by xi,
1 ≤ i ≤ n, in Part (1) of Theorem 2-7.
Thus, now we have an
algorithm for the SK representation of functions that are
defined by functional equations.
A comparison of Theorems 2-4 and 2-7 shows that
R-abstracts possess simpler properties than the abstracts in
general.
One exception is the property in Part (5) of Theorem
2-7, where we do not get any improvement by using R-abstracts.
The relation ↔n in the conclusion of that part cannot be
strengthened to ↔ , as the following counterexample will
R
R
show: Kx(Sx) ↔ x, A x:Kx(Sx) ≡ SKS, A x:x ≡ SKK,
and SKS ↔1 SKK, but not SKS ↔ SKK (cf. discussion after
Definition 1-12).
30
In spite of their simpler properties as compared to
abstracts in general, R-abstracts rapidly increase in length
and become tedious to compute as the number of indeterminates
for abstraction increases.
In Section 2.4, we will describe an
alternative, more practical algorithm for obtaining abstracts
that have almost the same reduction properties as R-abstracts.
31
2.3
The Lambda-Calculus
The previous section has introduced the notions of
indeterminates, ob forms, and abstracts for the purpose of
representing functions in SK.
It so turns out that the
functions encountered in the representation of programs are
defined solely in terms of formal variables; the resulting SK
representations are, therefore, just obs, rather than ob forms
containing indeterminates.
Thus, eventually, the use of
indeterminates and the generalization of obs to ob forms are
both dispensable; they are employed as a matter of notational
convenience only.
An alternative notion is that of lambda-expressions, which
closely resemble abstracts in their properties, but in which
the use of variables (indeterminates) is not as incidental.
Lambda-expressions are the objects of the lambda-calculus LC ,
which may be regarded either as an augmentation to SK or an
independent formal system that is similar to SK in several
respects.
We present below a brief description of lambdaexpressions for the sake of completeness and comparison with
abstracts.
For details, consult [8,9,33].
The symbols in the alphabet of LC are “(”, “)”, “λ” , “:”,
and a denumerable collection of variables.
A lambda-expression
(LE) is either a variable, or a word of the form (ef) or
(λx:e), where e and f are LE’s and x is a variable.
The LE (ef) is the application of e to f, and the LE
32
(λx:e) is the abstraction of e with respect to x.
To abbreviate LE’s, we may omit parentheses under the
convention that applications associate to the left and
abstractions to the right, with the former taking precedence
over the latter.
For instance, the LE
(λx: (λy: ((xy) (λz: (((xz) (yz)) u)))))
may be abbreviated to
λx: λy: xy(λz: xz(yz)u) .
As an additional convention, the above may be further
abbreviated to
λxy: xy(λz: xz(yz)u)
In the LE (λx:e), the leftmost occurrence of x is a
binding occurrence, and e is the range of that occurrence.
An
occurrence of a variable in an LE is bound if it is either
binding or in the range of any binding occurrence of the same
variable; otherwise, the occurrence is free.
If e,f1,...,fn
are LE’s and x1,...,xn variables, then
sub [f1,x1;...;fn,xn;e]
denotes the result of simultaneously substituting fi for all
free occurrences of xi (1 ≤ i ≤ n) in e.
The basic LC rules for transformation, called
contractions, are these:
33
(a)
λx:e →α λy:sub [y,x;e] ,
provided that y has no free occurrences in e, and no free
occurrence of x in e becomes a bound occurrence of y by
the substitution.
(b)
(λx:e)f →β sub [f,x;e] ,
provided that no variable with free occurrences in f has
bound occurrences in e.
(c)
λx:ex →η e, provided that x has no free occurrences in e.
Analogously to the development in the case of SK, we
define: immediate reduction (→im) of LE’s as the application
of an α-, β-, or η-contraction on their parts;
2
reduction (→)
as a sequence of immediate reductions; expansion (or,
respectively, α-, β-, η-, immediate expansion) as the converse
of reduction (or, respectively, α-, β-, η-contraction,
immediate reduction); and interconvertibility (↔) as a
possibly empty sequence of immediate reductions and expansions.
(The use of the same symbols → , →im and ↔ to represent the
different relations of SK and LC should not cause any
confusion.)
The Church-Rosser theorem holds for LC as well [9,
Ch. 4]: If e ↔ f, then there exists an LE g, such that e → g
and f → g.
2
But note the differences from SK:
The LE e is an immediate part of the LE’s (e f), (f e),
and (λx:e), where f is an LE and x is a variable.
A part of an LE is either the LE itself or a part of an
immediate part of the LE.
34
An LE is irreducible if no β- or η-contraction is applicable
to it even after any applications of α-contraction.
Given an
LE e, if there exists an irreducible LE f such that e ↔ f,
then f is a normal form of e.
The normal forms of LE’s are
unique only up to the applications of α-contraction.
The following properties of LE’s can be derived easily
from the above definitions.
(3-1) Theorem.
(1)
If none of y1,...,yn has a free occurrence in e and
no free occurrence of xi, 1 ≤ i ≤ n, in e becomes a bound
occurrence of the corresponding yi in e by the substitution
below, then
(2)
λx1...xn:e → λy1...yn:sub [y1,x1;...;yn,xn;e].
If no variable with a free occurrence in any of
g1,...,gn has a bound occurrence in e, then
(λx1...xn:e)g1...gn → sub [g1,x1;...;gn,xn;e].
(3)
If none of x1,...,xn has a free occurrence in e, then
λx1...xn:ex1...xn → e.
(4a) If e → e’, then λx1...xn:e → λx1...xn:e’.
(4b) If e ↔ e’, then λx1...xn:e ↔ λx1...xn:e’.
The similarity between LC and SK (augmented with ob forms)
becomes obvious when we set up a correspondence between
variables and indeterminates and then interpret
(1)
Ob forms by LE’s, by replacing S and K with λxyz:xz(yz)
and λxy:x, respectively;
(2)
R
LE’s by ob forms, by replacing λ with A .
35
With this interpretation, it is easy to see that whenever two
ob forms are mutually related by the SK reduction, their
corresponding LE’s are related by the LC reduction.
converse, however, is not true.
The
Here is a counterexample.
Let
f ≡ λx: (λxy:x)x((λxyz: xz(yz))x)
→ λx: sub [x,x; (λxyz:xz(yz))x,y; x]
≡ λx:x ≡ g , say.
Let
fC
and
gC
denote the SK interpretations of the LE’s f
and g, respectively; that is,
R
R
R
fC ≡ A x: (A xy:x)x ((A xyz: xz(yz))x) ,
R
gC ≡ A x:x ≡ SKK .
It can be verified easily that fC ≡ SKS.
Thus, in spite of the
relation f → g , it is not the case that fC → gC .
The above example also provides the explanation of this
dissimilarity of behavior between LC and SK.
During the
process of reduction in LC, contractions can be applied to any
part of an LE, including the one to be abstracted (i.e., to the
right of the colon) in an abstraction.
In SK an R-abstract is
an abbreviation for an ob form, and there are no provisions for
applying contractions on the part to be abstracted before the
whole abstract is computed.
(Compare Parts (4) of Theorems 2-7
and 3-1.) Thus, while all SK reductions can be carried out (in
36
terms of interpretations) in LC, additional reductions are
possible in LC that have no SK counterparts.
By supplementing
SK with some special rules, its reductions may be made to
correspond exactly with those in LC [9, p. 218].
The modified
reductions are termed strong; in contrast, SK reductions are
weak.
But in strengthening the reductions, one loses the
extreme simplicity of the SK reduction process as presently
based on S- and K-contractions alone.
Although weaker, the SK reductions completely suffice for
the modelling of programming languages, and in the sequel, we
describe our model in terms of SK only.
But, since all of the
reductions that we use also permit LC interpretations, the
model may just as well be regarded as being in LC; the only
needed modification is to replace the symbol A (the future
R
alternative to A ) by A, and to consider S and K as
abbreviations for the LE’s
respectively.
λxyz:xz(yz) and
λxy:x,
A purely LC formulation of our model is given in
[1].
We also remark that LC supports extensionality -- the
property that if fa ↔ ga for all a, then f ↔ g -- while SK
does not.
As a result, two representations of the same
intuitive function of n arguments are mutually interconvertible
in LC but, in general, only n-interconvertible in SK.
This,
however, is no hindrance at all: It is the mechanical process
37
of functional evaluation that we keep simple by adhering to
weak reductions.
But in making formal arguments about
functions, such as proving equivalence of functions and in
choosing function representations, we may freely employ ninterconvertibility, which is as easy to use in these cases as
interconvertibility.
38
2.4
Additional Obs
In this section, we define a number of obs and ob families
that will be employed in the representation of programs.
We
begin by introducing the most important of these:
(4-1) Definition.
I ≡ SKK ,
B ≡ S(KS)K ,
C ≡ S(S(KS)(S(KK)S))(KK) ,
W ≡ SS(SK) ,
Z ≡ KI ,
T ≡ CI ,
D ≡ WI ,
β ≡ B(BS)B,
Y ≡ B(SWW)B ,
Ω ≡ YK .
Clearly, I, B, C, and W are normal obs.
Though it may not
be so obvious from their definitions, the obs Z, T, D, β, and Y
can be easily seen to be normal also.
However, it will follow
from the property of Y given below that Ω does not possess a
normal form.
We shall use the term “rule” to designate frequently used
reduction properties.
We list a set of rules (including S- and
K-contraction for completeness) that can be easily derived from
the above definitions.
(4-2) Rule.
For all obs a, b, c, d:
(1)
Sabc → ac(bc) ,
(2)
Kab
→ a
,
(3)
Ia
→ a
,
39
(4)
Babc
→ a(bc) ,
(5)
Cabc
→ acb
,
(6)
Wab
→ abb
,
(7)
Zab
→ b
,
(8)
Tab
→ ba
,
(9)
Da
→ aa
,
(10)
βabcd → a(bd)(cd),
(11)
Ya
→ a(Ya) ,
(12)
Ωa
→ Ω
.
We may wish to incorporate some rules directly in an ob
reducing mechanism in order to avoid intermediate reduction
steps.
This places the selected rules at par with
contractions.
Equivalently, we may wish to extend the calculus
by admitting the obs with such rules as new primitive obs (in
addition to S and K), and the rules themselves as contractions.
In general, we have the choice of many rules for the same ob.
As an example, for the ob B we have:
(a)
B
→ S(KS)K
(b)
Ba
→ S(Ka)
(c)
Bab
→ S(Ka)b
(d)
Babc
→ a(bc)
(e)
Babcd → a(bc)d
For the sake of determinateness in reduction, however, we
should allow only one rule for each primitive ob.
if B is regarded as a primitive ob and (d) as the
(Note that
40
“B-contraction,” then, by Definition 1-4, the ob Bab has to be
considered irreducible whenever a and b are irreducible.)
Although SK is formulated in terms of S and K alone, we shall
state unique rules for the obs that are important enough to be
candidates for use as primitives in an extended calculus.
Now,
whenever any extensions to SK are stipulated, the following
question naturally arises: Do the Church-Rosser Theorem and
related properties remain valid in the extended calculus?
Fortunately, this theorem holds in very general situations
involving replacement rules (Rosen [32]).
It follows from
Rosen’s work that the theorem is supported, for example, by the
calculus containing S, K, and the obs of Definition 3-1 as
primitives and Rules 3-2 as contractions.
Furthermore, the
standard-order reduction algorithm continues to be valid in the
extended calculus.
We shall next describe the representation of natural
numbers and number-theoretic functions.
Following Church [8,
Chap. 3], we represent a natural number n by an ob n with this
desired property:
(4-3)
nxy
→
x(x( ... (x y) ...)) .
↑
n occurrences of x
The ob n is defined inductively in terms of the obs suc and 0,
representing the successor function and zero, respectively, as
follows:
41
(4-4) Definition.
suc ≡ SB
,
0
,
≡ Z
n+1 ≡ suc n .
That is, we have
0 ≡ Z ,
1 ≡ SBZ ,
2 ≡ SB(SBZ) ,
...
.
Using the above definitions, we immediately obtain:
(4-5) Rule.
(1)
0xy → y ,
(2)
n+l xy → x(nxy) ,
from which the property (4-3) follows by induction.
At this point, we introduce some notation due to
Curry [9]: We write a°b for Bab and a(n) for nBa.
Consequently,
we have:
(4-6)
Rule.
(1)
(a°b)c → a(bc),
(2)
a(n)bcl...cn → a(bc1...cn).
In particular:
(3)
K(n)ab1...bnc
→ ab1...bn
,
(4)
B(n)ab1...bncd → ab1...bn (cd).
In expressions involving ° we shall regard ° as being of lower
precedence than application and of higher precedence
42
than another ° at the right.
Thus a°bc will stand
for a°(bc), not (a°b)c, and a°b°c for (a°b)°c, not a°(b°c).
Note, however, that a°b°c ↔1 a°(b°c).
Anticipating the forthcoming discussion of tuples, we
next introduce the representation of ordered pairs and triples.
(4-7) Definition.
<a,b>
≡ C(Ta)b
,
<a,b,c> ≡ C<a,b>c .
The definition yields the following reduction properties.
(4-8) Rule.
(1)
<a,b>c → cab ,
(2)
<a,b>K → a
(3)
<a,b,c>d → dabc ,
(4)
<a,b,c>(K°K) → a,
and
<a,b>Z → b ,
<a,b,c>(KK) → b,
<a,b,c>(KZ) → c.
We can now describe the representation of the predecessor
function on natural numbers.
(4-9) Definition.
pred
≡
<S(BCT)suc°T0, <0,0>,K>.
(4-10) Rule.
0,
if n = 0,
pred n →
n-1,
if n > 0.
To prove this rule, let h ≡ S(BCT) suc°T0.
easily shown that
h <m, n> → <n, n+l> .
Then it can be
43
Hence,
pred n ≡ <h, <0,0>, K> n
→ n h<0,0>K
→ h(h(h( ... (h <0,0>) ... )))K
↑ n occurrences of h
<0,0>K → 0,
if n = 0 ,
<n-1,n>K → n-1,
if n > 0 .
→
It will be found convenient to define the ob families by
which the properties of K, I, and B are generalized in the
following manner.
(4-1l) Rule.
(1) Knab1...bn → a,
m
(2) I nal...an → am ,
n ≥ 1 .
n ≥ m ≥ l ,
m
(3) B nab1...bmc1...cn → a(blcl...cn)...(bmcl...cn),
m,n ≥ 1 .
Thus, we will have
K ↔2 K1 ,
1
1
1
I ↔1 I 1 , B ↔3 B 1 , S ↔3 B 2I,
a(n) ↔n+1 B1na .
The above rules can be realized by making the following
(4-12) Definition.
(1) Kn ≡ n K ,
(2)
n ≥ 1 ,
m
I n ≡ m-1 K (n-m K), n ≥ m ≥ l ,
m
(3) B n ≡ n(m-l(C(3 B) β ° TI)B) ,
m,n ≥ 1 .
44
It is easy to verify parts (1) and (2) of Rule 4-l1 from the
above definitions.
We shall prove part (3).
Let h ≡ C(3 B) β ° TI.
(*)
We first show by induction on m that
m-1 hBab1...bmc1 → a(b1c1)...(bmc1), (m ≥ 1).
This result is immediate for m = 1.
Assume it is true for m =
k; then
k h Bab1...bm+1c1
→ h(k-l h B) ab1...bm+1c1
→ (C(3 B) β ° TI) (k-1 h B) ab1...bm+1c1
→ C(3 B) β (TI (k-1 h B)) ab1...bm+1c1
→ 3 B(TI(k-1 h B)) β ab1...bm+1c1
→ 3 B(k-1 h BI) β ab1...bm+1c1
→ k-1 h B I(βa b1b2) b3...bm+1c1 ,
by 4-6 (2) ,
→ I(βab1b2c1)(b3c1)...(bm+1c1), by induction hypothesis,
→ a(b1c1)(b2c1) ... (bm+1c1) .
So (*) has been established.
induction on n.
To prove 4-1l (3) now, we use
For m ≥ 1, we have
m
B 1 ab1...bmc1 ≡ 1(m-l hB) ab1...bmc1
→ m-1 hB(0(m-lhB))a) b1...bmc1
→ m-l hB ab1...bmc1
→ a(b1c1)(b2c1) ... (bmc1) ,
by (*).
45
Hence assuming 4-11 (3) true for m ≥ 1 and n = k, we obtain
m
B k+1ab1...bmc1...ck+1 ≡ k+1(m-l h B) ab1...bmc1...ck+1
→ m-l hB (k(m-l hB)a) b1...bmc1...ck+1
→ k(m-l hB a(b1c1)...(bmc1)c2...ck+1 , by (*),
m
B k a(b1c1)...(bmc1)c2...ck+1
≡
→ a(b1c1c2...ck+1)... (bmc1c2...ck+1) ,
by induction hypothesis.
As shown by the next definition and the succeeding rues,
it is possible to generate the above ob families from single
obs. We can thus avoid postulating infinitely many primitives
in an extended calculus.
(4-13) Definition.
(1) K
≡ TK ,
(2)
I
≡ βB(CpredK)(CCK°Tpred) ,
(3)
B
≡ T°C(Cpred(C(3B) β°TI))B .
(4-14)
Rule.
(1) K n → Kn ,
(2)
m
I m n → In ,
m
(3) B m n → B n ,
Proof.
Omitted.
n ≥ l ,
n ≥ m ≥ l ,
m,n ≥ l .
46
Before listing further obs, we state an algorithm to
m
m
obtain abstracts in terms of the obs Kn , I n , and B n .
Unlike
the algorithm of Definition 2-5 in which abstraction is carried
out for one indeterminate at a time, the present algorithm
performs the abstraction with respect to all specified
indeterminates in a single step, and amounts to simple
replacements of indeterminates with special obs.
(4-15) Definition.
(1)
An initial component of an ob form is either the ob
form itself or the left immediate component of an initial
component of the form.
(2)
A primal component of an ob form is either its
shortest initial component, or a right immediate component of
one of its initial components.
Example.
The ob form e ≡ SK(x(KK)yz)(S(wz)(SSy))(xyz) has five
initial components, namely, S, SK, SK(x(KK)yz),
SK(x(KK)yz)(S(wz)(SSy)), and e itself; the primal components of
e are S, K, x(KK)yz, S(wz)(SSy), and xyz.
(4-16) Definition.
Let e be an ob form and x1,...,xn (n ≥ 1),
be indeterminates.
Then the *-abstract of e with respect to
x1,...,xn, denoted A*x1...xn:e, is the first of the following
ob forms, selected in the given order, according as the
condition is satisfied:
47
(1)
Kne , if xi oc
/
(2)
I
(3)
e for all 1 ≤ i ≤ n,
,
if
e ≡ x1...xn,
In
,
if
e ≡ xi for some 1 ≤ i ≤ n,
(4)
f
,
if
e ≡ fx1...xn , and xi oc
/
(5)
Bn I
i
m
f for all 1≤i≤n,
m
I n (A*x1...xn:f2)...(A*x1...xn:fm) ,
if e ≡ f1f2...fm ,
f1,f2,...,fm are primal
components of e, and f1 ≡ xi for some 1 ≤ i ≤ n,
m-1
(6) B n fl(A*x1...xn:f2)...(A*x1...xn:fm) ,
if e ≡ f1f2...fm , f1 is the longest initial
component of e such that xi oc
/
f1 for all 1 ≤ i ≤ n,
and f2,...,fm are primal components of e.
Note that for cases (5) and (6), we decompose the ob form
e into an initial component and a number of primal components,
with the initial component chosen to be either a single
indeterminate among x1,...,xn, if possible, or else the longest
possible ob form not containing any of x1,...,xn.
Example.
To find A*xyz:e, where e is as defined in the
previous example.
Diagrammed below is the decomposition of e
and its components according to the conditions prescribed in
(5) and (6) above.
48
SK (x
(KK)
y
z) (S
(w z) (SS y)) (x y z)
_ _
__ _
1 2
1
2
_
___
_ _
_ _____ ______
1
2
3 4
1
2
3
__ _______________ __________________ ________
1
2
3
4
Hence, A*xyz:e
3
4
1
2
2
3
1
3
1
2
≡ B 3 (SK)(B 3 II 3 (K3(KK))I 3 I 3 )(B 3S(B 3 w I 3 )(B 3 (SS)I 3 ))I .
By using Rules 4-10, it can be easily verified that,
except for parts (3b) and (4), Theorem 2-7 remains valid
when
R
A
is replaced by
A*.
It is possible to restore (3b) by
a slight modification in the above definition of abstracts.
Let A**x1...xn:e be specified similarly to A*x1...xn:e, except
for modifying the clause (4) in Definition 4-16 to
(4)
A**xl...xm-l:f, if for some 1 ≤ m < n,
e ≡ fxm...xn , and for m ≤ i ≤ n, xi oc
/
f .
(We consider A** xl...xm-l:f to be simply f when m = 1.) Let e
be the same ob form as before.
3
2
1
Then, we have
2
1
2
A**xyz:e ≡ B 3 (SK)(B 1 II 1 (K1(KK)))(B 3 S(K2w)(B 3 (SS)I 3 ))I .
It can be verified that with A** used instead of A
except (4) of Theorem 2-7 remain valid.
R
, all parts
49
In the sequel, we will drop the superscript on A
altogether, thereby leaving the abstraction algorithm
unspecified.
A function on natural numbers is partial
recursive if it can be defined using the following functions
and function-forming schemes [14]:
1.
Successor Function
S(x) = x+1 .
2.
Constant Functions
C q (x1,...,xn) = q, q a natural
n
number.
n
3.
Identity Functions
U i (x1,...,xn) = xi, 1 ≤ i ≤ n.
4.
Composition Scheme:
Given functions g,h1,...,hm,
to obtain f such that
f(x1,...,xn) = g (h1(x1,...,xn),...,hm(x1,...,xn)).
5.
Primitive Recursion Scheme.
Given functions g and h,
to obtain f such that
f(x1,...,xm,0) = g(x1,...,xm) ,
f(x1,...,xm,y+l) = h(x1,...,xm,y,f(x1,...,xm,y)).
6.
Minimalization Scheme.
Given a function g, to obtain
f such that
f(x1,...,xm) = (µy)[g(x1,...,xm,y) = 0]
= the least integer y, if one exists, such that
g(x1,...,xm,y) = 0 .
Now the obs suc,
Kn q
and
i
I n clearly represent the first
three functions of the above list.
Further, if the obs
50
g and hi are the representations of the functions g and hi,
m
respectively, then f ≡ B n gh1...hm represents the f of Scheme 4.
Thus, to complete the combinatory representation of partial
recursive functions, it only remains to provide the obs
primrecm and mnmlzm such that the definitions f ≡ primrecm h g
and f ≡ mnmlzm g may correspond to Schemes 5 and 6.
For this
purpose, we give the following definitions and rules, adapted
from Petznick [29] with minor modifications.
(4-17) Definition.
(1) primrec0 ≡ Axy:<Az:<suc(zK),x(zK)(xZ)>,<0,y>,Z> ,
2
(2) primrecm ≡ B 4 primmrec0 , m ≥ 1 ,
(3) mnmlz0 ≡ D(Axyz:zy(K(xx(suc y)z))y)0 ,
(4) mnmlzm ≡ mnmlz0(m)
(4-18)
(≡ m B mnmlz0) , m ≥ 1 .
Rules.
(1)
primrecm abc1...cmn
bc1...cm , if n = 0,
→
ac1...cmn-l(primrecmabc1...cmn-l), if n > 0.
(2)
mnmlzmab1...bm → n ,
provided that ab1...bm → 0, and, for all 0 ≤ p < n,
there exists some q > 0 such that ab1...bmp → q .
51
We shall make use of certain special forms of recursion in
specifying some ob sequences.
It is possible to give
individual, explicit definitions for the obs of these
sequences.
We indicate in the table below how all members of
such ob sequences can be generated from a single ob, thus
avoiding the need to postulate infinitely many primitives in an
extended calculus containing such obs.
(4-19)
Table.
Specification of the
Definition of the ob f
ob sequence fi
_____________________
such that f i → fi
_______________________
(1) f0 ≡ g ,
fn+l ≡ h fn .
f ≡ <h,g> .
(2) f1 ≡ g ,
fn+l ≡ h fn .
f ≡ <h,g>°e pred .
(3) f0 ≡ g ,
fn+l ≡ h n .
f ≡ C(SI(K°(h°pred)))g .
(4) f0 ≡ g ,
fn+l ≡ h n fn .
(5) f0 ≡ g ,
f ≡ primrec0 h g .
f ≡ primrec0 <B,h>g .
fn+la1...an+1 ≡ h(fna1...an)an+1 .
(6) f0 ≡ g,
f ≡ primrec0(C°(CBh°TB))g.
fn+la1...an+1 ≡ ha1(fna2...an+1) .
52
For each entry in the Table 4-19, the relation fn → fn
can be verified from the definition of f.
prove the case of entry (3).
f ≡ C(SIp)g.
For example, we
Let p ≡ K°(h°pred), so that
Then:
f0 ≡ C(SIp)g0 → SIp0g → I0(p0)g → 0(p0)g → g ≡ f0.
fn+1 ≡ C(SIp)gn+1 → SIpn+1g → In+1(pn+1)g
→ n+l(pn+1)g → pn+l(n(pn+1)g)
≡ (K°(h°pred))n+l(n(pn+l)g)
→ K(h(pred n+l))(n(pn+lg)
→ hn ≡ fn+l .
To facilitate the representation of a succession of
function applications, we introduce the ob family nestn:
(4-20)
Definition.
nest0 ≡ I ,
nestn+1a1...an+l ≡ Ba1(nestn a2...an+l) ,
[a1,...,an] ≡ nestn a1...an .
(4-21) Rule.
[a1,a2,...,an]b → a1(a2(...(an b)...)) .
Note the following properties of nests:
[a,...,a] ↔1 n a ,
↑ n occurrences
[a1,...,am,b1,...,bn] ↔1 [a1,...,am]° [b1,...,bn] .
53
The purpose of the next set of obs is to represent
functional operators for permuting and duplicating the
arguments of functions.
These obs thus generalize the effect
of C and W.
(4-22) Definition.
(1) rotl1 ≡ I ,
rotln+1 ≡ (BC°B) rotln ,
(2) rotr1 ≡ I ,
rotrn+1 ≡ C(B°B)C rotrn ,
n ≥ 1.
n ≥ 1.
m
(3) swap n ≡ [rotrm , rotrn , rotlm+1 , rotln] , l≤m≤n .
m
n
i
i
(4) perm i1,...,im ≡ B n I I 1 n ... I m n ,
l ≤ ij ≤ n for all 1 ≤ j ≤ m.
(5) dup0 ≡ I ,
dupn+1 ≡ dupn°(W(n+1)rotrn+1)(n+1) , n ≥ 1.
(4-23) Rule.
(1) rotln a b1b2...bn → a b2...bn b1 ,
n ≥ 1 .
(2) rotrn a b1...bn-1bn → a bnb1...bn-1 ,
n ≥ 1 .
m
(3) swap n a b1...bn → a b1...bm-1bnbm+1...bn-1bm
l ≤ m ≤ n .
(4)
n
perm i1,...,ima1...an → ai1...aim ,
l ≤ ij <n for all l ≤ j ≤ m .
(5)
dupn a b1...bn → a b1... bnb1... bn .
,
54
Proof.
(1), (2), and (5) by induction on n,
(3) by (1) and (2), and (4) by Rule 4-10 (3).
Our representation of ordered tuples is adopted from
Church [8].
The essential idea is to regard the tuple
<a1,...,an> as the abstract Ax: xa1... an , that is, to define
tuples so as to obtain the rule
<a1,...,an>b → ba1...an .
(Two special cases of ordered tuples, namely, pairs and
triples, and their associated rules were introduced earlier
(4-7 and 4-8).
In addition to the tuple-forming operators, we
will require a number of obs to represent various manipulations
on tuples, such as inserting, retrieving, or changing elements.
Here are the necessary definitions and rules.
(4-24) Definition.
(1) tup0 ≡ I ,
tupn+1 al...an+l ≡ C(tupn a1...an)an+1 ,
<a1,...,an> ≡ tupn a1...an ,
n ≥ 0 .
(2) insert ≡ C .
m
m
(3) elem n ≡ I n ,
l ≤ m ≤ n .
m
(4) replace n ≡ [rotlm+1,rotrm,K]tupn,
2
m
m
(5) fput n ≡ B n I(rotrn+1 replace n ) ,
(6)
m
m
funtup n = B n tupn ,
l ≤ m ≤ n .
l ≤ m ≤ n .
l ≤ m ≤ n .
55
(4-25) Rule.
(1)
<a1,...,an>b → ba1...an .
(2)
insert <a1,...,an>b → <a1,...,an,b> .
(3)
elem n a1...an → am ,
(4)
replace n b a1...an → <a1,...,am-1,b,am+1,...,an> ,
m
l ≤ m ≤ n .
m
l ≤ m ≤ n .
m
<a1,...,an> (replace n b)
→ <a1,...,am-1,b,am+1,...,an> ,
l ≤ m ≤ n .
m
(5) fput n fa1...an → <a1,...,am-1,fa1...an,am+1,...,an> ,
l ≤ m ≤ n .
m
<a1,...,an> (fput n f)
→ <a1,...,am-1,fa1...an,am+1,...,an> ,
l ≤ m ≤ n .
(6)
Proof.
m
funtup n f1...fm a1...an → < f1a1...an,...,fma1...an>.
Omitted
We claim that there exist obs nest, rotl, rotr, tup, elem,
and replace possessing the following reduction properties:
56
nest n → nestn , n ≥ 0 ,
rotl n → rotln , n ≥ 1 ,
rotr n → rotrn , n ≥ 1 ,
tup
n → tupn ,
n ≥ 0 ,
m
e1em m n → elem n , l ≤ m ≤ n ,
m
replace m n → replace n , l ≤ m ≤ n .
The definitions of nest, rotl, rotr, and tup follow directly
from Table 4-19 and Definitions 4-20,22,24; in addition, we can
take
elem ≡ I ,
replace ≡ Axy: [rotl (suc x), rotr x, K] (tup y) .
It should be noted that, indeed, each ob sequence that we have
introduced so far, or will introduce in the sequel, can be
generated from a finite number of obs.
CHAPTER 3
BASIC PROGRAMMING FEATURES
In this chapter, we undertake the representation of the
more elementary features of high-level programming
languages, postponing the discussion of jumps and procedures
to later chapters.
We use the ALGOL 60 [27] terminology and
notation, whenever possible, to express programming language
features.
3.1
An Overview
To construct our model, we start with the representations
of the atomic constituents of program, such as constants and
variables.
We then develop the rules for obtaining the
representations of larger and larger programming constructs by
combining the representations of their syntactic units in
certain ways, eventually deriving the rules for representing
whole programs.
Throughout this development, we are guided by
intuitive interpretations of programming constructs as
functions.
There are several different ways in which a program may be
regarded as a function, depending upon what we consider to be
the arguments of the program and what we regard as the finally
computed results.
These different functional
57
58
interpretations of programs may result in different choices
of the representations of individual programming constructs.
We will take the view that it is the external input-output
behavior that most appropriately characterizes a program, and
choose our representations with the goal of making this
behavior as explicit as possible.
Consider, for example, the
program:
begin integer a,b,c;
read a; read c; b := a+c; write b; b:=b-2xc;
write b
end
(We use read and write as standard statements for performing
single-item input-output operations).
As far as the external
input-output is concerned, the above program behaves like a
two-argument function which produces as value two quantities,
the sum and difference of its arguments.
Thus, this program
may be intuitively interpreted as the function f given by
f(x,y) = <x-y,x+y> .
(i)
The function f is representable in SK by an abstract
f ≡ Axy:<x-y,x+y>
(ii)
having the reduction property
fxy → <x-y,x+y> .
(iii)
59
(Although the expressions x-y and x+y are not exactly ob
forms, they can be easily translated to be such -- as we will
soon see.)
Accordingly, we would like to set up the model in
such a manner that the representation of the above program may
turn out to be an ob f, satisfying (iii).
So constructed, the
model would, in essence, enable us to abstract out of a program
code the function from the input space to the output space that
the program computes.
For, f represents precisely this input-
output function.
More generally, let P be a program, i1,...,ip, its inputs,
and o1,...,oq its outputs.
Then we would like that the
representations provided by our model satisfy the reduction
relation
(1-1)
{P}{i1 }...{ip } → <{o1 }...{oq }> ,
in which the representations are denoted (anticipating a
forthcoming notation) by enclosing within braces the symbols
for the corresponding represented entities.
The subsequent sections will show how the representations
of various programming constructs may be chosen to fulfill the
above requirement.
60
3.2
Variables
For each program that we wish to represent in our model,
we shall need a fixed correspondence between the variables
declared in the program and the indeterminates of (the
augmented) SK.
Now in block-structured programming languages,
it is permissible to employ the same identifier to denote
different program variables as long as those variables have
different scopes.
In choosing the correspondence between
program variables and indeterminates, it will not be necessary
to distinguish between any two identically denoted variables
that are declared in disjoint blocks.
But it will be necessary
to distinguish all the variables that are declared in a set of
nesting blocks.
(To distinguish two such variables denoted by
the same identifier, it suffices, for example, to superscript
the identifier by the respective block level numbers -- zero
for the outermost (program) block, and n+l for the blocks
immediately enclosed by a block at level n.) The correspondence
between program variables and indeterminates will be set up by
assigning distinct indeterminates to distinct variables (in the
above sense) in some order.1
1
Since we
We shall assign single indeterminates to both simple
variables and array variables, however, the treatment of
arrays is deferred to a later section, and until that
discussion all variables are meant to be simple.
61
have not specified the alphabet for indeterminates, we shall,
for convenience in expressing our representations, denote the
indeterminates by the same symbols by which the corresponding
program variables are denoted.
The representation of a programming construct in a given
program depends upon, among other things, the variable
declarations in whose scope the construct appears.
To account
for this, we need the notion of environment defined as follows:
The environment of a construct in a program is a list of all
the program variables that have been declared in the blocks
enclosing the point at which the construct occurs.
In this
list, the variables are to be arranged in their order of
declaration within individual blocks, with the blocks taken in
the innermost to the outermost order.2
From what has been stated earlier about distinguishing
program variables, it follows that the variables constituting
an environment are all distinct.
Example.
Consider the following schematic program, in which it
is assumed that the omitted statements indicated by ellipses do
not contain declarations.
2
When the program contains procedures, the environments may
also include formal variables and a number of other
variables which are not explicitly declared in the program;
these additional variables will be introduced in Chapter 5.
62
A:begin integer x,y;
B:...;
begin integer y,z;
C:...;
end;
begin integer x,w,z;
D:...,
end
end
From our view-point, this program makes use of six
0
0
1
1
1
distinct variables, namely, x ,y ,y ,z ,x , and
superscripts indicate block level numbers.
0
0
1
1
w , where the
For simplicity, let
1
us omit the superscripts from x ,y ,z , and w .
Then the
environments of the statements labelled A (i.e., the whole
program), B, C, and D are, respectively, the null list
1
1
(), (x,y), (y ,z,x,y), and (x ,w,z,x,y).
In general, the SK representation of a construct depends
upon the construct’s own environment as well as the
environments of its constituents.
We denote the SK
representation of a construct X appearing in the environment E
by {X }E.
We drop the subscript from the above notation if the
representation of X is the same in all environments (in which X
63
can legally occur).
A formula specifying the representation of a construct in
terms of its environment and the representations and
environments of its constituents will be referred to as a
representation rule.
In such a formula, the environments of
the constituents will generally be omitted if they are the same
as the environment of the construct under representation.
64
3.3
Constants, Operations, Relations
The general criterion for choosing the SK representations
of the values of the various types employed in programming
languages and associated operations and relations may be stated
thus: Let * denote a unary operation and ** a binary operation
or relation.
Then for all operands a and b of the proper types
for which * and ** are defined, it should be the case that
{*}{a} → {value of (*a)} ,
{**}{a}{b} → {value of (a**b) .
In this way, it becomes possible to interpret the computation
of values as simply the SK reduction process.
Of course, the
above criterion may be met by several different
representations, in which case the choice is dictated by the
simplicity of the resulting obs.
We begin with the Boolean values.
The values true and
false are represented by the obs K and Z, (Definition 2.4-1),
respectively.
The motivation behind this choice is that it
leads to a very simple representation of conditional
expressions; namely,
{if b then c else d) ≡ {b}{c}{d}
(i)
Quite short representations of logical operators can then be
provided by using McCarthy’s well-known technique of expressing
these operators in terms of conditionals [23].
65
In particular, we obtain:
(2-1)
Definitions and Rules.
(1)
true ≡ K ,
true a b → a .
(2)
false ≡ Z ,
false a b → b .
(3)
¬ ≡ <false,true> ,
¬ a → a false true .
(4)
∧ ≡ CC false ,
∧ a b → a b false .
(5)
∨ ≡ T true ,
∨ a b → a true b .
(6)
imp ≡ CC true ,
imp a b → a b true .
(7)
eqv ≡ CS ¬ ,
eqv a b → a b (¬ b) .
It is an easy matter to verify that the above presented
obs correctly represent the corresponding logical operators.
For example, it is seen that
imp true true
→ true true true
→ true
imp true false
→ true false true
→ false
imp false true
→ false true true
→ true
imp false false → false false true → true
So that a conditional expression may be recognizable as
such even when represented in SK, we make the following trivial
definition and restate the representation rule (1).
(2-2)
Definition.
if ≡ I .
(2-3)
Representation Rule.
{if b then c else d } ≡ if {b}{c}{d} .
66
Let us now turn to the representation of arithmetic in
SK.
We will only be concerned with integers and rational
numbers.
(The type called “real” in the programming parlance
will be termed “rational” here.) The representation of natural
numbers has already been described (Definition 2.4-4).
Following the procedure common in analysis, one can consider
integers and rational numbers to be equivalence classes of
natural numbers and integers, respectively.
For convenience in
carrying out reductions with their representations, it seems
preferable, however, to represent these numbers in terms of
uniquely selected members of the equivalence classes they stand
for.
Thus, an integer p is traditionally defined to be the set
of all pairs
<m,n>
of natural numbers in and n, such that,
intuitively, p is a solution of the equation
m = n+p; but we
prefer to define the SK representation of p to be the
representation of that particular pair in the set which has the
smallest m and n (at least one of these being necessarily
zero).
Again, a rational number r is the set of all pairs
<p,q> of integers p and q such that r intuitively satisfies
p = q × r; but we prefer to represent r by the representation
of that pair for which q is positive, p and q are relatively
prime, and, furthermore, if p = 0, then q = 1.
67
Numbers of different types denoted by the same symbols in
a programming language are in reality different entities
possessing different ob representations.
We denote them by
underlined numerals, unsubscripted in the case of natural
numbers, and with subscripts Z and Q added for integers and
rational numbers, respectively.
Thus, the obs 3, 3Z , and 3Q
and represent the natural number 3, the integer 3 and the
rational number 3.
As discussed above, we define them as
follows:
3
≡ suc (suc (suc 0)) ,
where suc ≡ SB,
0 ≡ Z ,
3Z ≡ <3, 0> ,
3Q
≡ <3Z,1Z> ≡ <<3,0>,<1,0>> .
Additional examples:
0Z
≡ <0,0>,
0Q
≡
<0Z,1Z>
-3Z
≡ <0,3>,
-3Q
≡
<-3Z,1Z>
-2.6Q ≡
<-13Z,5Z >
≡
<0Z,13Z>
≡
<<0,0>,<1,0>> ,
≡
≡
<<0,3>,<1,0>> ,
<<0,13>,<5,0>> .
Having settled upon the representation of numbers
themselves, let us turn to the representation of operations and
relations defined on numbers.
We denote the representations by
the corresponding algebraic symbols, again unsubscripted in the
case of natural numbers and subscripted with the letters Z and
Q in the case of integers and rational numbers, respectively.
Thus, +, +Z, and +Q represent natural number, integer, and
rational addition, respectively, and are to be so
68
defined that, for example,
+ 3 2 → 5 .
+Z 3Z -2Z → 1Z ,
i.e., +Z <3,0><0,2> → <1,0> .
+Q 5/6Q -4/9Q → 7/18Q
.
Obs representing the successor and predecessor functions
on natural numbers were defined earlier (Definition 2.4-4,2.49).
Using the method of representing recursively defined
functions given in Section 2.4, the SK representations of other
operations and relations on natural numbers can be obtained
from their well-known recursive definitions [14].
For strong
combinatory calculi, this is done in Church [8]; for the weaker
SK reductions, some representations are given in Petznick [29).
Finally, to represent integer and rational operations, we can
make use of the definitions of these operations in terms of,
respectively, the natural number and integer operations on the
components of the pairs representing their operands.
integer operations for example.
Consider
First we will require an ob
normlZ to represent the “normalization” operation of converting
an arbitrary pair of natural numbers in the equivalence class
denoting an integer to the unique pair chosen for the CC
representation of that integer; e.g.,
normlZ <l6,5> → <11,0> ,
Having represented the proper subtraction and minimum selection
69
operations on natural numbers by the obs -̇
and min,
respectively, we would need the rule
normlZ <m,n> → <-̇ m (min m n), -̇
n (min m n)> .
In view of Rule 2.4-8(2), an adequate definition for this
purpose is:
normlZ ≡ Ax:< -̇ (xK)(min(xK)(xZ)), -̇ (xZ)(min(xK)(xZ))> .
Now we can represent integer addition and subtraction (in terms
of natural number addition on the components of the integer
operands) by the obs defined to satisfy the reduction relations
+Z <a,b> <c,d> → normlZ <+ a c , + b d> ,
-̇ Z <a,b> <c,d> → normlZ <+ a d , + b c> .
As additional examples, let us consider the familiar
programming operations of type-conversion from integers to
rational numbers, and the “mixed addition” of rational and
integer operands giving a rational result.
The obs float and
+QZQ representing these operations have to satisfy, for
example:
float 2Z → 2Q ,
+QZQ -3.14Q 2Z → -1.14Q .
70
The following definitions clearly suffice for these obs:
float ≡ Ax:<x,lZ> ,
+QZQ ≡ Axy:+Q x(float y) .
Not all operations, of course, are so easy to deal with.
Furthermore, the operations such as the exponentiation to
fractional powers, which lead to irrational numbers, can be
represented in our scheme only by defining them in terms of
functions that approximate the results to some desired
precision, using the techniques for representing functions that
will be described later.
However, the actual details of
representing various arithmetic operations and relations are
not crucial to our model, for this model is not intended to be
used in studying the purely numerical aspects of programs.
The
purpose of the discussion in this section is simply to indicate
that it is possible to represent arithmetic in SK, and to
sketch a way of carrying out this representation.
71
3.4
Expressions
We limit ourselves at present to the expressions that do
not contain function designators.
(This restriction will be
lifted when procedures are discussed.)
According to the
requirements imposed by programming languages, any variable
occurring in such an expression must also occur in the
environment of the expression.
its environment.
Let e be an expression and E
Then, in view of the SK representations
chosen for operations and constants, the representation {e}E
will be defined by induction on the (parse) structure of e to
be the following ob form:
1)
If e consists of a constant represented by c, then
{e}E ≡ c.
2)
If e consists of a program variable corresponding to
the indeterminate x, then {e}E ≡ x.
3)
If e consists of a k-ary operation (or relation)
represented by o, with the subexpressions el,...,ek as
operands, then {e}E ≡ (o {e1}E ,..., {ek}E).
It follows that the SK representation of an expression may
be obtained simply by writing the expression in the prefix
notation, with all operator-operands combinations
parenthesized, and then replacing all operators and operands by
their representations.
It further follows that the
72
representation of an expression is the same in all environments
in which it can legally appear.
Thus, in accordance with a
convention stated in Section 3.2, we may omit the mention of
environment in denoting the representation of expressions.
Consider, for example, the following expression in which
x, y, z denote program variables:
x + if y ≠ 0 then z+y else l5.
(i)
In the prefix form, this expression may be written as:
(+ x (if (≠ y 0) (+ z y) 15)).
(ii)
In accordance with the conventions stated in Section 3.2, let
us use the symbols x, y, z for indeterminates as well as the
program variables.
Now if the program variables have been
declared to be all of type integer, and the value of the above
expression is to be of type integer also, then the expression
may be represented by the ob form
+Z x (if (≠Z y 0Z) (+Z z y) 15Z).
(iii)
On the other hand, if the program variable x and the result are
of the type rational, and y and z of type integer, then the
expression may be represented by
+Q x (float (if (≠Z y 0Z) (+Z z y) 15Z)).
(iv)
where the ob float represents the type-conversion operation
73
mentioned in the previous section.
But for closer resemblance
between the given expression and its representation, we find it
preferable to write, instead of (iv),
+QZQ x (if (≠Z y 0Z) (+Z z y) 15Z) ,
(v)
with the ob +QZQ representing the “mixed” addition of a
rational number to an integer, producing a rational number as
value.
For conciseness of notation in stating the representation
of expressions, we shall henceforth assume that all typeconversions are absorbed within mixed operations as above.
Furthermore, we shall omit all type indicating subscripts,
leaving the types to be inferred from the context.
For
example, we shall abbreviate (v) to
+ x (if (≠ y 0) (+z y) 15) .
(vi)
No serious ambiguity will arise out of the above convention,
because, except for using natural numbers in a few, explicitly
indicated, instances, we shall use the numbers and operations
of type integer only.
We shall often need the abstract of the representation of
an expression with respect to the indeterminates representing
the variables in the environment of the expression.
The
procedure of Definition 2.4-16 is particularly easy to apply in
this case.
Specifically, for the special case of
74
expression representations, we may state the following
(4-1) Abstraction Algorithm.
Let e be the ob form representing
an expression which appears in the environment (v1,...,vn).
Then to obtain Av1... vn:e, rewrite e, replacing
k
(1) each ob o representing a k-ary operation by (B n o)
i
(2) each indeterminate vi, 1 ≤ i ≤ n, by I n , and
(3) each ob c representing a constant operand by (Knc).
Example.
Let (x,y,z,w) be the environment of the
expression
if y = 218 ∧ x+3 < -z then z+(7+y) else
if x × y ≥ z then entier (x/z) else -12.
The above expression may be represented by the ob form
e ≡ if (∧ (= y 218) (< (+ x 3)(minus z))) (+ z (+ 7 y))
(if (≥ (x × y) z) (entier(/ x z)) -12) ,
where minus and entier have obvious significance.
Using the
above procedure, we obtain
3
2
2
2
2
2
1
Axyzw:e ≡ B 4 if(B 4 ∧ (B 4 = I 4 (K4 2l8))(B 4 <(B 4 + I 4 (K43))
3
1
2
3
2
2
(B 4 minus I 4 ))) (B 4 + I 4 (B 4 + (K4 7)I 4 ))
3
2
2
1
2
3
1
2
1 3
(B 4 if (B 4 ≥ (B 4 × I 4 I 4 )I 4 ) (B 4 entier (B 4 /I 4 I 4 ))
(K4 -12)) .
75
It is only in the representation of expressions that we
are compelled to employ indeterminates.
In representing larger
constructs, such as statements, which contain expressions as
syntactic units, the expression representations will always be
used as parts of abstracts of the above form, eliminating all
indeterminates.
76
3.5 Assignments
Before discussing any particular type of statement, we
will first indicate the general idea behind our SK
representations.
Consider a given statement S of a program.
Let (v1,...,vn) be the environment of S, and denote by F the
section of the program following S and extending all the way to
the program end.
(F will sometimes be referred to as the
program remainder of S.) The two parts of the program, one
consisting of F alone, and the other composed of S and F
together, may be interpreted as two functions φ and φ’,
respectively, of the arguments v1,...,vn.
With this
interpretation in mind, the effect of the statement S is to
transform φ into φ’.
As the representation of S, therefore, we
take precisely the function (to be accurate, the functional
operator) σ given by
(σ(φ))(v1,...,vn) = φ’(v1,...,vn)
(i)
which accomplishes the above transformation.
Using the Schönfinkel interpretation of functions
(Section 2.2), the above relation may also be written as
σ(φ,v1,...,vn) = φ’(v1,...,vn) .
(ii)
Now suppose we can somehow express the right-hand-side of
(ii) in terms of the function φ, the variables v1,...,vn,
77
and possibly some constants.
Then we may take (ii) to be the
functional equation defining σ, with v1,...,vn, and even
φ, as formal arguments.
(Note that while the domains of the
arguments v1,...,vn are the values of the corresponding program
variables, the domain of φ consists of the program remainders
considered as functions.) Now by interpreting (ii) in
combinatory terms, and by abstracting the ob form representing
its right-hand-side with respect to the indeterminates
φ,v1,...,vn, we may obtain a definition of σ as an ob.
We remark that if the statement S is modelled as above by
the ob σ, then the execution of S is modelled by the reduction
of
σ φ v1 ... vn ,
in which the symbols v1,..., vn denote the representations of
the values of the corresponding variables immediately prior to
the execution of S, and φ denotes the representation of the
program remainder of S.
A key step in representing a programming statement is to
define a suitable equation of the form (i) or (ii) for it.
(The choice of φ’ is, of course, based on our intuitive
understanding of the effect of the statement.) For the sake of
motivation, we will include the details of this step in
describing the first few of our representations.
78
Let us now look at the assignment statement vi:= e in the
environment (v1,...,vn).
The φ’ in this case is obtained from
φ by setting the argument vi to e.
Thus, in effect, this
assignment statement behaves as the function σ such that
(σ(φ))(v1,...,vn) = φ’(v1,...,vn)
= φ’(v1,...,vi-1,e,vi+1,...,vn) .
In SK notation, this amounts to
σφv1...vn → φv1...vi-1 {e}(v1,...,vn)vi+1...vn) .
Accordingly, we adopt the following SK representation of
assignment statements:
(5-1)
Representation Rule.
{vi:= e }(v1,...,vn) ≡ Aφv1...vn: φv1...vi-1 {e}vi+1...vn) .
(We recall from Section 3.2 the convention that in a
representation rule, the environments of all representations
are considered to be the same as that of the construct under
representation, unless specified otherwise.
Also, we assume in
the above representation that any type conversion needed for
the assignment has been incorporated within e itself.)
It has been mentioned earlier that only the variables
79
contained in the environment of an expression can occur in the
expression.
Thus, no indeterminates other than v1,...,vn can
occur in the ob form {e} in the above representation rule.
It
follows from the abstractions specified in that rule that the
SK representation of an assignment statement is an ob, not an
ob form containing occurrences of indeterminates.
Note that the multiple assignments of ALGOL 60 [27] and
the collateral (parallel) assignments of ALGOL 68 138] present
no special problem.
Omitting the formal rules for their
representation, we simply illustrate their treatment in the
following example.
Example.
Presented side by side below are some assignment
statements and their SK representations.
Note that the
environment of the first two statements is (x,y), and of the
1
0
next three is (z,y ,x,y ); the superscripts in the latter
environment are block level numbers, and are used to
distinguish the two variables designated by the same
identifier.
Program
Statement Representations
begin integer x,y;
x:=2;
Aφxy:φ2y (or, Aφx:φ2)
y:=x+l9;
Aφxy: φx(+xl9)
begin integer z,y;
y:=x-5;
x:=y:=z+(x+y) ;
1
0
0
Aφzy xy :φz(-x5)xy
1
0
1
1
0
Aφzy xy :φz(+z(+xy ))(+z(+x y ))y
80
1
0
0
Aφzy xy :φy1zxy
(y:=z, z:=y);
...
end
end
In
order
to
express
the
representation
of
assignments
explicitly as obs rather than abstracts, we introduce some new
obs.
Although their names are suggestive of the programming
actions they represent, we emphasize that they
are just ordinary obs, with no imperative notions attached to
them.
(5-2)
Definition.
2
evalm ≡ C(B n I°rotrn+1) ,
n ≥ 1.
2
storei ≡ swap i+2K ,
i ≥ 1.
i
assign n ≡ CBstorei°evaln ,
n ≥ i ≥ 1.
The following reduction properties are easy to derive.
(5-3)
Rule.
evaln fφx1...xn → φ(fx1...xn)x1...xn
storei φex1...xi → φx1...xi-1e
.
.
i
assign n fφ x1...xn → φx1...xi-1(fx1...xn)xi+1...xn
Hence, we have the following alternative to (5-1).
.
81
(5-4)
Representation Rule.
i
{vi:= e }(v1,...,vn) ≡ assign n (Av1...vn:{e}) .
Example.
(x,y).
Consider the statement y := x+19 in the environment
In this case, we have
{e} ≡ {x+19} ≡ +x19 ,
2
1
Axy:{e} ≡ B 2+I 2 (K219) ,
by (4-1),
2
2
1
{y := x+l9}(x,y) ≡ assign 2 (B 2 + I 2 (K219)) .
To conclude this section, we point out the fact that we
have eliminated the concepts of memory and address from our
model, and have reduced the concept of assignment to that of
substitution or function evaluation.
82
3.6
Compound Statements
Consider the compound statement S begin S1;S2 end
appearing in the environment (v1,...,vn).
of the program that follows S.
Let F be the segment
We can interpret the program
segments F and (S;F) to be two functions φ and φ’,
respectively, of the arguments v1,...,vn , and we are
interested in the representation σ of S with the functional
transformation property
(σ(φ))(v1,...,vn) = φ’(v1,...,vn) .
Now the execution of (S;F) has precisely the same effect as
(S1;S2;F).
Denoting by φ* the functional interpretation of the
program segment (S2;F), and by σ1 and σ2 the representations of
the statements S1 and S2 , respectively, we have
(σ1(φ*))(v1,...,vn) = φ’(v1,...,vn) ,
(σ2(φ))(v1,...,vn) = φ*(v1,...,vn) .
The above functional conditions can be expressed in SK as the
following reduction relations:
σ φ v1...vn → φ’v1...vn ,
σ1φ*v1...vn → φ’v1...vn ,
σ2φ v1...vn → φ*v1...vn ,
These relations will certainly hold if we choose
83
φ* ≡ σ2φ ,
φ’ ≡ σ1(σ2φ) , and hence, σ ≡ Aφ:σ1(σ2φ) .
The generalization to the case of an n-component compound
is now obvious.
So we are led to the following SK
representation of compound statements:
(6-1) Representation Rule.
{begin S1;S2;...;Sn end} ≡ Aφ:{S1}({S2}(...({Sn}φ)...))
or,
≡ [{S1),{S2},...,{Sn}]
(where the notation [...] for nests is as introduced in
Definition 2.4-20).
Notice the convenient fact that in the above nest the
individual statement representations appear from left to right
in the same order in which the statements occur in the compound
(cf.
Stratchey [36]).
Example.
The representation of compound statements is
illustrated below.
Individual statement representations are
shown on the same line as the statements (on the last line for
multiple-line statements), and are given names for reference
purposes.
The environment is assumed to be (x,y).
Statements
Representations
(i) begin
x := 2;
a ≡ Aφxy:φ2y
84
y := x+3;
b ≡ Aφxy:φx(+x3)
x := y+x
c ≡ Aφxy:φ(+yx)y
end
d ≡ Aφ:a(b(cφ))
(ii) begin
y := 5;
e ≡ Aφxy:φx5
x := y+2
f ≡ Aφxy:φ(+y2)y
end
g ≡ Aφ:e(fφ)
The compound statements (i) and (ii) are intuitively
equivalent.
model?
How can their equivalence be demonstrated in our
The obs representing the statements (i) and (ii),
namely, d and g, must have the same interpretation as a
function of the variables φ, x, and y.
Alternatively, d and g
must perform the same reduction when applied to the same obs φ,
x, and y; that is,
d φ x y ↔ g φ x y .
(*)
To verify (*), we reduce both sides to the same ob.
g φ x y ≡ Aφ:e(fφ)φ x y
→ e(fφ) x y,
since φ oc
/ e and φ oc
/ f,
85
≡ (Aφxy:φx5)(fφ) x y
→ f φ x 5
≡ (Aφxy:φ(+y2)y) φ x 5
→ φ (+ 5 2)5
→ φ 7 5 .
Similarly, it is easy to see that
d φ x y → φ 7 5 .
In general, to show that two statements appearing in the
same environment of n variables are equivalent, we need to
prove that the SK representations f1 and f2 of those statements
are mutually (n+1)-interconvertible (Definition 2.1-l1).
however, is an unnecessarily strict condition.
This,
It is often the
case that in all the intended executions of a program (that is,
with the input data satisfying the program specifications), the
values of program variables range over certain restricted
domains only.
In such cases, the equivalence of two statements
in the environment of n variables may be established by proving
that, for x1,...,xn representing not all arbitrary obs but only
the possible values corresponding to the variables x1,...,xn of
the environment, and for all obs φ, it is the case that
f1 φ x1...xn ↔ f2 φ x1...xn
.
86
3.7
Blocks
Next, let us consider a block S whose head declares the
variables u1,...,um and initializes these to the values3
c1,...,cm , and whose body consists of the statements
S1,...,Sp, in that order.
The execution of S can be broken
down into three operations performed in succession:
1) Extension of the existing environment by the variables
u1,...,um (initialized at c1,...,cm).
2) Execution of the compound begin S1;...;Sp end.
3) Deletion of the, variables u1,...,um from
the environment.
Let these three operations be denoted by the functions α,
β, and γ.
Let (v1,...,vn) be the environment of S.
Then with
the obvious significance of other symbols, we have
(α(φ))(v1,...,vn) = φ(c1,...,cm,v1,...,vn)
(β(φ))(u1,...,um,v1,...,vn) = (σ1(σ2(...(σp(φ))...)))
(u1,...,um,v1,...,vn)
(γ(φ))(u1,...,um,v1,...,vn) = φ(v1,...,vn)
(σ(φ))(v1,...,vn) = (α(β(γ(φ))))(v1,...,vn)
By expressing the above in SK notation, and making use of
proper abstractions and simplifications, we obtain
σ ≡ Aφv1...vn: σ1(σ2(...(σp(Au1...um:φ))...))c1...cmv1...vn .
3
We assume that the expressions c1,...,cm do not contain
the variables u1,...,um; they may, however, contain the
variables in the environment of S.
87
Consequently, we choose the following representation of blocks.
(7-1) Representation Rule.
{begin <type> u1 := c1;...;<type> um := cm;
S1;...;Sp end}(v1,...,vn)
≡ Aφv1...vn:{Sl}F({S2}F(...({Sp}F(Au1...um:φ))...))
{cl}E...(cm}Ev1...vn
,
where E ≡ (v1,...,vn) and F ≡ (u1,...,um,v1,...,vn) .
(We assume that the expressions ci include any needed typeconversions.)
Using the notation of nests and tuples (Definitions 2.420, 2.4-24), an explicit combinatory description of the above
abstract is
[<{cl}E,...,(cm}E> , [{S1}F,...,{Sp}F ,Km]]
In the case that the variables are left uninitialized in
the block-head -- as is normal in ALGOL 60 -- any arbitrary ob
can be used for {ci} in the above representation.
One might
wish to use for this purpose an ob which would play the role of
the everywhere undefined function.
This function is modelled,
for example, by the ob Ω (Definition 2.4-1) having the property
88
Ω a → Ω for all a.
It should be noted, however, that Ω does
not possess a normal form.
As a result, if Ω is used in place
of the missing ci’s in (7-1), then the presence of any
variables that remain undefined throughout the program
execution would cause the program representation to behave as
if the program contained an infinite loop.4
Being the representation of statements, the components
{Si}F, 1 ≤ i ≤ p, of the right-hand-side of (7-1) do not
contain any indeterminates.
But being the representations of
expressions in the environment (v1,...,vn), {ci}, 1 ≤ i ≤ m, may
possibly contain v1,...,vn.
If the variables declared in the
block head are not initialized, then, by recourse to a suitable
abstraction algorithm (Theorem 2.2-4(3)), the indeterminates
v1,...,vn can be dropped from the right-hand-side of (7-1).
We
thus obtain the following simplified representation:
(7-2) Representation Rule.
{begin <type>u1;...;<type>um;S1;...;Sp end}(v1,...,vn)
≡ Aφv1...vn:{Sl}F({S2}F(...({Sp}F(Au1...um:φ))...))ΩΩ...Ω
m times ↑
where F ≡ (u1,...,um,v1,...,vn) .
4
This situation may be avoided by using the ob
Ω’ ≡ D(B(S(BSC))(BC(C(KD)))K
instead of Ω. It is easy to verify both that Ω’ is
normal and that, for all a, Ω’a → Ω’ .
89
Note that if only constants are used to initialize the declared
variables, then again the variables vi can be dropped, and the
representation is similar to (7-2), except that the constants
are used instead of the corresponding Ω.
Example.
be (w).
The environment of the following block is assumed to
The individual statements and their representations
are given side by side below.
The representations have been
given identifying names for reference purposes.
Statements
Representations
begin integer x:=5,y;
y := x-7;
a ≡ Aφxyw:φx(-x7)w
begin integer z;
z := 3+y;
b ≡ Aφzxyw:φ(+3y)xyw
x := z × x
c ≡ Aφzxyw:φz(×zx)yw
end
d ≡ Aφ:b(c(Az:φ))Ω
end
e ≡ Aφ:a(d(Axy:φ))5Ω
Explicit combinatory definitions of the above obs, in
accordance with our previous representation rules, are as
follows:
2
2
1
2
2
2
1
a ≡ assign 3 (B 3 - I 3 (K37)) ,
3
b ≡ assign 4 (B 4 +(K43)I 4 ) ,
1
2
c ≡ assign 4 (B 4 x I 4 I 4 ) ,
90
d ≡ [<Ω>,[b,c,K1]] ,
e ≡ [<5,Ω>,[a,d,K2]] .
91
3.8
Input-Output
We shall assume for simplicity that the program input and
output operations are each restricted to a single file.
A file
of items al,...,an will be represented by the tuple
< {al},...,{an}> .
(The empty file is represented by the null tuple < > ≡ I.)
For
given ob forms u and v, we will abbreviate the ob form insert u
v by u,v ; also we will denote u,v,w by u,v,w , and so on.
By
Rule 2.4-25 (2), we have
<xl,...,xn>,y ≡ <xl,...,xn,y>
I,xl,...,xn ≡ <xl,...,xn>
,
,
so that “,” may be regarded as the operation of writing on a
file, and the file resulting from writing an item a on a given
file b may be represented by {b},{a} .
Now let S be a statement appearing in the environment
v1,...,vn of a program, and let σ be the ob representing S.
In our discussion so far, σ has been defined as an abstract of
the form
Aφv1...vn:...
(*)
with the indeterminate φ standing for the program remainder of
S.
Accordingly, the execution of S has been modelled by the
reduction of the ob
σ φ v1...vn
,
92
in which the underlined symbols denote the representations of
the values of the corresponding variables immediately prior to
the execution of S.
In order to take input-output into
account, we will generalize the representations so as to model
the above execution by the reduction of the ob
(8-1)
σ φ v1...vn w u1 u2...um ,
th
with w denoting the output file and ui the i
of the m items
remaining on the input file at the moment of execution.
(As
soon as an item is read, it is supposed to disappear from the
input file.)
This arrangement requires that the
representations of statements be generally of the form
A φ v1 ... vn o i1 ... im : ... ,
where o,i1,...,im are the extra indeterminates corresponding to
the output file and input items.
It must be evident, however,
that the representations of those statements which do not
involve input-output can be simplified back to the form (*) by
choosing abstracts properly.
Furthermore, in the case of
input-output statements, the following choice of SK
representations is obvious:
(8-2)
Representation Rule.
{read vj}(v1,...,vn) ≡ Aφv1...vno: φv1...vj-1ivj+1...vno ,
{write e}(v1,...,vn) ≡ Aφv1...vno: φv1...vn o,{e}
where e is some expression to be output.
,
93
In order to provide explicit ob representation of inputoutput statements, we introduce the following obs
(8-3) Definition.
j
j+1
(1) read n ≡ swap n+3 K(n+1) ,
(2) writen ≡
1 ≤ j ≤ n ,
2
[B n+1 SK(n),K,(CC)(n)]
.
(8-4) Rule.
j
(1) read n φx1...xn o i → φx1...xj-1 i xj+1...xn o ,
(2) writen fφx1...xno → φx1...xn o,fx1...xn .
Proof of (2).
writen fφx1...xno
2
≡ [B n+1 SK(n),K,(CC)(n)]fφx1...xno
2
→ B n+1 SK(n)(K((CC)(n)f))φx1...xno , by Rule 2.4-21,
→ S(K(n)φx1...xn)(K((CC)(n)f)φx1...xn)o
→ K(n)φx1...xno(K((CC)(n)f)φx1...xno)
→ φx1...xn((CC)(n)fx1...xno) , by Rule 2.4-6,
→ φx1...xn(Co(fx1...xn)o)
→ φx1...xn(Co(fx1...xn)) ≡ φx1...xn o,fx1...xn .
In view of the above rules, we propose the following
alternative to (8-2):
(8-5)
Representation Rule.
j
{read vj}(v1,...,vn) ≡
read n ,
{write e}(v1,...,vn) ≡
writen (Av1...vn:{e}) .
94
3.9
Programs
Let the input file initially presented to a given program
consist of items i1,...,ip , and let o1,...,oq constitute the
items of the final output file produced by the program.
As
remarked in Section 3.1, we wish to choose a program
representation so as to obtain the relation
{program }{i1 }...{ip } → < {o1 },...,{oq }> .
(i)
Now the execution of a particular statement of the program is
modelled by the reduction of an ob given by (8-1) in the
previous section.
Suppose that as an instance of such a
statement we take the entire outermost block of the program.
Recalling the significance of symbols used in connection with
(8-1), we obtain the following conditions:
σ ≡ {program block }
n = 0 as the environment is null ,
w ≡ I , as the output file may be considered empty at the
start of the program ,
m = p , and uj = ij , l ≤ j ≤ p.
Furthermore, in place of φ , the “null” program remainder, we
may arbitrarily choose to employ the ob I.
On substituting
these values, the execution of the program is seen to amount to
the reduction of the ob
{program block } I I {i1 }...{ip } .
(ii)
95
Next, consider (8-1) again -- but this time for the case when
the entire program has been executed.
Now we have:
σ ≡ I, the null program segment,
n = 0 , as the environment is null,
w = < {o1 },...,{oq }> , representing the final
output file,
m = 0 , assuming the program exhausts the input file,
φ ≡ I.
Thus, (8-1) in this case becomes the ob
I I < {o1 },...,{q } > ,
which reduces to
< {o1 },...,{q } > .
(iii)
If our representations work properly, then the ob
(ii) should reduce to the ob (iii); that is,
{program block }I I {i1 }...{ip } → < {o1 },...,{oq }>.
(iv)
Comparing (i) and (iv), we obtain:
(9-1) Representation Rule.
{program} ≡ (program block) I I .
(9-2) Remarks.
(1) From (iv) and (9-1)
it follows that
< {i1 },...,{ip } > {program}
→
< {o1 },...,{oq }> ,
96
that is,
<input file> [program}
(2)
→
<output file> .
In the ob representing a program, the component
({program block} I) will be found to be of interest by itself;
we will refer to it as the routine of the program.
Example.
Following is the representation of the simple program
mentioned at the beginning of Section 3.1.
Statements
Representations
begin integer a,b,c;
read a;
f ≡ Aφabcoi:φibco
read c;
g ≡ Aφabcoi:φabio
b := a+c;
h ≡ Aφabc: φa(+ac)c
write b;
j ≡ Aφabco:φabco,b
b := b-2xc;
k ≡ Aφabc:φa(-b(×2c))c
write b
j
end
m ≡ Aφ:f(g(h(j(k(j(Aabc:φ))))))ΩΩΩ
Since the ob in represents the program block, the
representation of the whole program is p ≡ mII.
Now it can be
verified that, for all integers a and b,
p a b → <a+b,a-b> .
Thus the program representation
p
indeed abstracts out the
input-output behavior of the program (cf. Section 3.1).
97
The execution trace of the above program, when run with the
integers 5 and 3 as data items, is reflected in the following
SK reduction.
p 5 3 ≡ m I I 5 3 → f(g(h(j(k(j(Aabc:I))))))Ω Ω Ω I 5 3
→ g(h(j(k(j(Aabc:I))))) 5 Ω Ω I 3
→ h(j(k(j(Aabc:I)))) 5 Ω 3 I
→ j(k(j(Aabc:I))) 5 (+ 5 3) 3 I
→ j(k(j(Aabc:I))) 5 8 3 I
→ k(j(Aabc:I)) 5 8 3 I,8 ≡ k(j(Aabc:I)) 5 8 3 <8>
→ j(Aabc:I) 5 (-8 (× 2 3)) 3 <8> → j(Aabc:I) 5 2 3 <8>
→ (Aabc:I) 5 2 3 <8>, 2 → (Aabc:I) 5 2 3 <8,2>
→ I <8,2> → <8,2> .
3.10
Conditional Statements
Recall that the SK representation of a Boolean expression
b has the property
{b} p q → p , if b has the value true,
→ q , if b has the value false.
In view of the above property, we choose the representation of
a two-branch conditional statement as follows:
(10-1)
Representation Rule.
{if b then S1 else S2 }(v1,...,vn)
≡ Aφv1...vn: {b}{S1}{S2}φv1...vn
.
98
For the purpose of representation, a one-branch conditional
statement (an if statement, in ALGOL 60 terminology) may be
viewed as a two-branch conditional with a dummy or “donothing” statement for the second branch.
When appearing in
the environment (v1,...,vn), the “do-nothing” statement can
obviously be represented by
Aφv1...vn: φv1...vn
that is, I.
,
Substituting the “do-nothing” statement for S2 in
(10-1), we obtain the
(10-2) Representation Rule.
{if b then Sl}(v1,...,vn) ≡ Aφv1...vn:{b}{S1}Iφv1...vn .
In order to describe the above representations explicitly
as obs, we first introduce a new ob sequence and its associated
reduction rule.
(10-3)
Definition.
(10-4)
Rule.
3
condn ≡ β°(B n I).
condn bs1s2φx1...xn → bx1...xn(s1φx1...xn)(s2φx1...xn) .
It is easy to see that if b is a Boolean expression, then for
all ob forms p, q, and r, the following interconvertibility
relation holds:
{b}pqr ↔ {b}(pr)(qr)
Applying this relation to (10-1), we may
.
99
obtain the following alternatives to (10-1) and (10-2).
(10-5) Representation Rule.
(1) {if b then S1 else S2 }(v1,...,vn)
≡ Aφv1...vn: {b}({S1}φv1...vn)({S2}φv1...vn)
≡ condn (Av1...vn: {b}{S1}{S2}
.
(2) {if b then Sl}(v1,...,vn)
≡ Aφv1...vn: {b}({S1}φv1...vn)(φv1...vn)
≡ condn (Av1...vn: {b}{S1}I
3.11
.
Arrays
Arrays can be interpreted as tuples and combinations of
tuples.
An array of a single dimension is represented by a
tuple of the representations of the individual array elements,
taken in the order of the lowest to the highest subscript.
An
array of dimension n+1 is represented by a tuple whose elements
are the representations of the n-dimensional subarrays (or
slices, in the ALGOL 68 terminology [38]) obtained by fixing
the first subscript in turn from the lowest to the highest
possible value.
For example, the array A [l:2, 1:3] is
represented by
< < {A11},{A12},{A13}> , < {A21},{A22},{A23}> > ,
where (Aij} is the representation of the array element Aij.
in the case of simple variables, an array identifier can
As
100
itself be used for the indeterminate assigned to the array
variable.
With the above interpretation of arrays, we next describe
the representation of subscripted variables in expressions,
assignments to subscripted variables, and array declarations.
In this description, we assume for simplicity that all arrays
have the lowest subscript bound of 1.
To obtain the correct
representation in the case of an array one of whose subscript
bounds, l, is different from 1, one simply needs to first
increment the corresponding bound and subscript expressions
throughout the program by 1-l.
1) Subscripted variable as an operand in an expression
The representation in this case is just the corresponding
element of the tuple representing the array.
Thus, given the
declaration <type> array v [1:n], we have, on the basis of Rule
2.4-25 (3),
i
{v [i]} ≡ v elem n
.
This representation is inadequate, since, in general, n and i
are given as expressions rather than constants, and their
values may not be known at the time of SK translation of the
program.
However, we have seen (cf. end of Section 2.4) that
there exists an ob elem such that for all obs a and b if a → i
and b → n, where i, n represent natural numbers i, n such that
101
1 ≤ i ≤ n,
i
elem a b → elem n .
Hence, given the array declaration v [1:e], we specify
{v [f]} ≡ v(elem [f}{e}) .
More generally, for the array v [1:e1,...,1:em], we have
{v [f1,...,fm]} ≡ v(elem {f1}{e1})...(elem {fm}{em}).
2)
Assignments to subscripted variables
In this case, the representation consists in replacing
the designated element of the tuple representing the array with
the representation of the new value.
arrays of a single dimension only.
Let us first consider the
We have already seen
(Section 2.4, end) that there exists an ob replace such that,
for all natural number representations i, m such that 1 ≤ i ≤ m
and for all ob forms a1,...,am,b,
<a1,...,am>(replace i m b) → <a1,...,ai-1,b,ai+1,...,am> .
Hence, given the declaration <type> array vj[1: e], we have
{vj[f] := g}(v1,...,vn)
≡ Aφv1...vn: φv1...vj-1(vj(replace {f}{e}{g}))vj+1...vn .
The representation in the case of a higher dimensional
array involves the replacement of all slices of the array
102
that are affected by the assignment.
It is easy to see that,
when the array vj is declared to be of bounds [l:e1,...,l:em],
the following is a suitable representation:
{vj (f1,...,fm] := g }
≡ Aφv1...vn: φv1...vj-1hvj+1...vn ,
where
h ≡ vj(replace {f1}{e1}(
vj((elem {f1}{e1}) (replace {f2}{e2}(
vj((elem {f1}{e1})(elem {f2}{e2}) (replace {f3}{e3}(
...
vj((elem {f1}{e1})...(elem {fm-1}{em-1})
replace {fm}{em}{g}))... ))) ))) )) .
3)
Array declaration
We treat array declarations in the same way as the
declaration of simple variables with respect to environments
and the representation of initialized variable values.
However, there is the following exception: if an array is not
initialized at the time of declaration, the block
representation is obtained by assuming all the array elements
to be Ω.
Thus, for an array with the bound pairs [1:2,1:3],
the initial value is represented by <<Ω,Ω,Ω>,<Ω,Ω,Ω>>.
103
Since, in general, array bounds may be specified by
expressions, we need to create tuples of arbitrary dimensions
and sizes in which all elements are Ω.
This will be possible
by means of the ob tupinit having the property
tupinit 1 m → <Ω,Ω,...,Ω> ,
↑ m elements
tupinit n+l m1...mn+1 → <a,a,...,a> ,
↑ m1 elements
(*)
where a ≡ tupinit n m2...mn+1 .
In order to define tupinit, we need the following
definition, making use of some obs of Section 2.4:
(11-1) Definition.
(11-2) Rule.
maketup ≡ β(TW)pred tup .
maketup n x →
<x,..,x> , for integer n > 0.
↑ n times
(11-3) Definition.
tupinit0
≡
Ω ,
tupinitn+1 a1a2...an+1
≡ maketup a1 (tupinitn a2...an+1) .
Now from Table 2.4-19 we can define an ob such that for all
natural numbers n ≥ 0,
tupinit n → tupinitn
.
104
It is quite straightforward to check that with this choice of
tupinit, the relations (*) are indeed satisfied.
Example.
The array representations discussed above are
illustrated on the following block which is assumed to occur in
the environment (n).
Statements
Representations
begin integer array p [1:n],
q [1:2,1:3]; integer r;
r := q [n,n+1];
a ≡ Aφpqrn:φpq(q(e1em n 2)
(elem(+ n 1)3))n
p [r]:= r+3
b ≡ Aφpqrn:φ(p(rep1ace
rn(+ r 3)))qrn
end
σ ≡ Aφn:a(b(Apqr:φ))
(tupinit 1 n)
<<Ω,Ω,Ω>,<Ω,Ω,Ω>>Ωn
CHAPTER 4
ITERATION AND JUMP STATEMENTS
4.1
Recursive Specification of Obs
In dealing with program loops, we shall need obs having
the property that they are equiform to one or more components
of certain obs to which they reduce.
That is, these obs are to
possess given reduction properties of the form
F → ...F...F...
.
(i)
We refer to such obs as recursively specified obs, and describe
two approaches to define these.
One approach to define recursively specified obs is to
admit them as primitive obs, taking the respective properties
required of them as the reduction rules associated with them.
Since the reductions rules so added are recursive, in the sense
that they reduce an ob in terms of itself, it is not at all
obvious that the Church-Rosser property would hold in the
extended calculus.
But it follows from the work of Rosen [32]
that the Church-Rosser property is indeed preserved by such
extensions, and, consequently, most other properties of
reduction, such as the uniqueness of normal forms and the
correctness of the standard-order reduction algorithm, also
continue to be valid.
105
106
Another approach to defining the obs specified by the
properties of the form (i) is to look for solutions of (i),
treating such formulas as reduction relations involving an
unknown.
Now, in general, (i) may be satisfied by more than
one solution, so that we may have the choice of different
explicit definitions for the same ob.
There is, however, no
reason to expect that these different definitions of an ob are
compatible to each other or to the definition of the ob as a
new primitive -- compatible in the sense that all reduction
sequences, which start with an ob having a recursively
specified ob as a component and which use the different
definitions of the recursively specified ob, yield the same
normal form (if any).
In fact, incompatibilities do occur, as
the following trivial example indicates: Let F be an ob
specified by
F → F,
and let it be required to reduce the ob G ≡ SF.
By the
definition of reduction (Definition 2.1-4), the given property
of F is satisfied by every ob.
In particular, with F ≡ S and
F ≡ K chosen as two possible definitions of F, the same ob G
may be reduced to SS in one case and to SK in another!
Moreover, both these results are in conflict with the one
obtained by taking F as a primitive ob and F → F as the
associated reduction rule.
For, then, G does not even have a
107
normal form!
Thus, not all solutions of (i) are acceptable for a
definition of the ob F.
Following Morris [26], to characterize
those solutions of (i) for which the resulting definitions of
the ob F are compatible with the definitions of the first
approach (of taking (i) as a reduction rule), we may proceed
thus.
Let us introduce a partial order on obs as follows:
For obs a and b we say that a is extended by b, in symbols, a ≤
b, if, for all obs c, it is the case that ca ↔ cb whenever ca
possesses a normal form.
For example, it can be shown that Ω ≤
b for all obs b, where Ω is as given in Definition 2.4-1.
Now,
the particular solutions of (i) that we are interested in have
the property that they are extended by all solutions of (i).
In other words, for an explicit definition of the ob F
specified by (i), we can take a minimal solution of (i) (with
respect to ≤).
For example, consider the relation F → F again.
Since
this relation is satisfied by all obs, Ω is a minimal solution
for it.
Thus, F ≡ Ω may be taken as a definition of the ob
specified by F → F.
Under this definition of F, the ob G ≡ SF
does not possess a normal form.
This agrees with the result
obtained by taking F as a primitive ob, with F → F as its
associated reduction rule.
To obtain an explicit definition of the ob F given by (i),
we may proceed as follows: Let x be an indeterminate,
108
and let
H ≡ Ax: ...x...x...
be an abstract with respect to x of the ob form obtained from
the right-hand-side of (i) by replacing the components equiform
to F by x.
Now
YH → H(YH) ,
by Rule 2.4-1(18),
→ ...(YH)...(YH)... ,
Hence, YH is seen to be a solution of (i).
by Theorem 2.2-4.
It has been shown
by Morris [26] that this solution is also minimal.
Consequently,
F ≡ YH ≡ Y(Ax:...x...x...)
(ii)
is an explicit definition of the ob specified by (i).
In general, (i) has infinitely many, mutually
noninterconvertible, minimal solutions, which are, however,
equivalent in the sense that they all have the same intuitive
interpretations as functions.
The choice of any one of these
for the explicit solution of (i), such as YH in (ii), is rather
arbitrary.
To leave this choice unspecified, while emphasizing
the minimality of the chosen solution, one may employ the µnotation of deBakker [3].
In this notation, the minimal
solution of (i) is designated by the µ-expression
µx:...x...x... ,
109
where, the ob form to the right of the colon is obtained from
the right-hand-side of (i) by replacing F with the
indeterminate x.
Since the formula (i) has the appearance of a relation,
which may not necessarily suggest that it is intended to define
anything, we shall use the notation
F ≡
...F...F...
to indicate that the ob F is being defined as specified by (i).
The above treatment of recursively specified obs can also
be generalized to include the simultaneous recursive
specification of several obs, such as
F1 → H1F1...Fn ,
...
(iii)
Fn → HnF1...Fn ,
where F1,...,Fn do not occur as components in H1,...,Hn.
The
definitions of F1,...,Fn may be obtained as follows:
1)
The F’s specified by (iii) are considered primitive
obs whose associated reduction rules are just the
formulas (iii).
2)
The F’s specified by (iii) may be explicitly defined
as the minimal solutions of the system of
110
reduction relations (iii).
An explicit solution may be obtained as follows: Consider
<H1F1...Fn,...,H1F1...Fn>
n
← funtup n H1...Hn F1...Fn,
by Rule 2.4-25,
n
← <F1,...,Fn>(funtup n H1...Hn)
n
← <funtup n H1...Hn><F1,...,Fn> .
Hence, we may take, for 1 ≤ i ≤ n,
n
i
Fi ≡ Y <funtup n H1...Hn> elem n .
As before, we shall employ the notation
F1 ≡ H1F1...Fn ,
...
Fn ≡ HnF1...Fn ,
to indicate the definition of the obs F1,...,Fn by means of the
formula (iii).
111
4.2 Iteration Statements
The representation of the for statement of ALGOL 60 is
obtained by expressing this statement in terms of the simple
(non-ALGOL 60) while loop of the form while ... repeat... .
To
represent the latter, consider the statement while b repeat S
appearing in the environment (v1,...,vn).
Calling this
statement by the name T, we may (recursively!) describe it, for
the purpose of SK representation, as
if b then begin S;T end .
Now the formulas for the representation of compound and
conditional statements, (3.6-1) and (3.10-5(1)) respectively,
are applicable to the above statement, so that its
representation {T} is, recursively, the ob
Aφv1...vn: {b}((Aφ: {S}({T}φ))(φv1...vn) (φv1...vn)
↔n+1 Aφv1...vn: {b}({S}({T}φ))φv1...vn .
Thus, we adopt the
(2-1)Representation Rule.
{while b repeat S}(v1,...,vn)
≡ µx: Aφv1...vn: {b}({S}(xφ))φv1...vn .
Alternative definitions of the same ob, call it X, are
X ≡ Aφv1...vn: {b}({S}(Xφ))φv1...vn ,
X ≡ Y(Axφv1...vn: {b}({S}(xφ))φv1...vn) ,
X ≡ condn {b} [{S},X] I .
112
Example.
At this point, we illustrate the SK representations
introduced so far by means of a complete program.
Also, as an
application of the model, we derive the correctness of the
program in terms of its representation.
Given below are the
individual statement representations, shown on the same line as
the statements (or on the last line for multiple line
statements), and have been designated names for reference
purposes.
begin integer x,y;
read x;
a ≡ Aφxyoi:φiyo
y := 0;
b ≡ Aφxy:φx0
begin integer z;
z := 0;
c ≡ Aφzxy:φ0xy
while z < x repeat
begin
y := l+y+2×z;
d ≡ Aφzxy:φzx(+(+1y)(×2z))
z := z+l
e ≡ Aφzxy:φ(+z1)xy
end
end while
f ≡ Aφ:d(eφ)
g ≡ Aφzxy:(<zx)(f(gφ))φzxy
h ≡ Aφ:c(g(Az:φ))Ω
write y
end
j ≡ Aφxyo: φxy o,y
k ≡ Aφ: a(b(h(j(Axy:φ))))ΩΩ
{program ≡ P ≡ kII
113
We wish to prove that on reading a nonnegative integer n,
2
this program will print out the integer n .
According to our
input-output conventions, we need to show that
2
P n → <n > ,
for all integers n ≥ 0 .
(i)
This is done in four steps, as follows:
(a) We show that, for all obs φ, and all integers n and i,
g φ i n i
2
g φ i n i
2
2
→ φ i n i
,
→ g φ i+1 n (i+1)
2
if i ≥ n,
(ii)
, if i < n .
(iii)
By the definition of g, we obtain
g φ i n i
2
2
→ (< i n) (f(gφ)) φ i n i
.
If i ≥ n, then (< i n) → false, so that (ii) is immediate.
Otherwise, (< i n) → true, and the above ob
2
→ f(gφ)i n i
2
→ d(e(gφ))i n i
→ gφ i+1 n (i+1)
2
2
→ e(gφ)i n(+(+ 1 i )(× 2 i))
.
(b) Next, for all integers n and i such that 0 < i ≤ n, we have
2
g φ 0 n 0 → g φ i n i .
This is proved by induction on i.
(iv)
From (iii) one easily
verifies (iv) both for i = 1, and for i = j+l ≤ n when the case
for i = j < n is assumed.
114
(c) Next, we claim that for all integers n ≥ 0, it is
the case that
2
h φ n 0 → φ n n
.
(v)
For, we have
h φ n 0
≡ (Aφ:c(g(Az:φ))Ω)φ n 0
→ c(g(Az:φ))Ω n 0
→ g(Az:φ) 0 n 0 .
Now if n = 0, then from (ii) it follows that
2
g(Az:φ) 0 n 0 → (Az:φ) n n n
→ φ n n
2
.
On the other hand, if n > 0, then for the case i = n (iv)
yields
2
g(Az:φ) 0 n 0 → g(Az:φ) n n n
2
→ (Az:φ) n n n
2
→ φ n n
(d)
by (ii)
.
Finally, to prove (i) we simply use the definitions
of the obs a through k, obtaining, for all integers n ≥ 0,
P n ≡ k I I n → a(b(h(j(Axy:I)))) Ω Ω I n
→ b(h(j(Axy:I))) n Ω I
→ h(j(Axy:I)) n 0 I
2
→ j(Axy:I) n n I
2
by (v)
2
→ (Axy:I) n n I,n
→ I,n
2
2
→ <n >
115
Returning to the discussion of iteration statements, we
can express the general for statement of ALGOL 60 in terms of
the simple while loop treated above.
For example, we can
reformulate the statement
for vi := e1 step e2 until e3 do S
as
begin vi := e1
while (vi - e3) × sign(e2) ≤ 0 repeat
begin S; vi := e1 + e2
end
end
.
The latter form can then be represented as an ob by employing
the representations of compound and while statements.
Omitting
the details of derivation, we list below the SK representations
for the three cases of for list elements, namely, arithmetic
expression, (ALGOL 60) while element, and step-until element:
{for vi := e do S}(v1,...,vn)
≡ Aφv1...vn: {S}φv1...vi-1{e}vi+1...vn .
{for vi := e while b do S}(v1,...,vn)
≡ µx:Aφv1...vn:(Avi:{b}){e}({S}(xφ))φv1...vi-1{e}vi+1...vn
≡ Y(Axφv1...vn:(Avi:{b}){e}({S}(xφ))φv1...vi-1{e}vi+1...vn).
{for vi := e1 step e2 until e3 do S}(v1,...,vn)
≡ Axφv1...vn: (Y(Axφv1...vn:{(vi-e3)×sign(e2) ≤ 0}
({S}(Av1...vn:xφv1...vi-1{vi+e2}vi+1...vn))
φv1...vn))φv1...vi-1{e1}vi+1...vn .
116
4.3
Jump Statements
We regard the execution of the statement S ≡ goto L in a
program as the substitution of the part of the program
following L for the one following S.
This viewpoint provides
us with the representation of both labels and jump statements.
A label is identified with the part of the program
following it.
To be accurate, the representation of a label L
occurring in a program P is taken to be the routine (Remark
3.9-2(2)) of the program P’ obtained from P by deleting all the
statements, but retaining the declarations, that appear above
L.
This representation can be obtained in a simpler manner by
using the following inductive scheme: Let the label L occur in
a block b whose declared variables are v1,...,vn .
(1)
If L is followed by statements S1,...,Sm, and a label M,
in that order, all within b, then
{L} ≡ {S1}({S2}(...({Sm}{M})...))
(2)
If S1,S2,...,Sm are the statements following L to the end
of b, then
{L} ≡ {S1}({S2}(...({Sm}(Av1...vn:N))...)) ,
where N ≡ I, if b is the outermost block, else N is the
representation of the program part following b, that is, of the
(possibly imaginary) label immediately after the end of b.
117
According to the rules of ALGOL, the label to which a jump
can be made must be in a block which is the same as, or outer
to, the block containing the jump statement.
It follows that
(the list of variables constituting) the environment of a jump
statement must contain the environment of the referred label as
a final segment.
Suppose (v1,...,vn) is the environment of the
statement S ≡ goto L, and (vm,...,vn), where 1 ≤ m ≤ n, is the
environment of L, and let φ represent as usual the program
remainder of S.
The execution of S causes the program to
compute the function {L}(vm,...,vn) instead of φ(v1,...,vn).
Hence, the representation of S can be taken to be the ob
Aφv1...vn: {L}vm...vn ,
or the (n+1)-interconvertible ob
Aφv1...vm-1: {L} .
Thus, we choose:
(3-1)Representation Rule.
{goto L, where the environment of L is (vm,...,vn),
1≤m≤n}(v1,...,vn)
≡ Aφ:(Av1...vm-1:{L}) ≡ Km {L} .
It is sometimes convenient, specially in connection with
conditional statements, to write the right-hand side in the
alternative forms:
Aφv1...vn:{L}vm...vn ,
Aφv1...vn:(Av1...vm-1:{L})v1...vn .
118
Example.
The representation of goto statements and labels is
illustrated by means of a complete program.
The program below
has been derived from the program given in the previous example
simply by expressing the while loop in terms of goto’s.
As
another application of the model, we prove the (input-output)
equivalence of the two programs.
As before, the representations of individual statements
are shown on the same line as the statement, or on the last
line for a multiple-line statement, and are designated
identifying names.
The obs common to the representation of
both programs have the same names.
The label M serves to illustrate the case (1) of label
representations discussed above; it is otherwise superfluous.
begin integer x,y;
read x;
a ≡ Aφxyoi:φiyo
y := 0;
b ≡ Aφxy:φx0
begin integer z;
z := 0;
L:
c ≡ Aφzxy:φ0xy
if z=y then goto N
else goto M;
M:
d’≡ Aφzxy:(=zy)(Az:N)Mzxy
y := y+2×z+l;
e’≡ Aφzxy:φzx(+(+y(×2z))1)
z := z+l;
f’≡ Aφzxy:φ(+zl)xy
goto L
g’≡ Aφ:L
end;
h’≡ Aφ:c(d’(e’(f’(g’(Az:φ)))))Ω
119
N:write y
j ≡ Aφxyo:φxy o,y
end
k’≡ Aφ:a(b(h’(j(Axy:φ))))ΩΩ
{program} ≡ P ≡ k’II
L ≡ d’M
M ≡ e’(f’(g’(Az:N)))
N ≡ j(Axy:I)
We wish to prove that the above program and the program of
the previous example produce the same output when executed with
the same non-negative integer as the input data.
That is, in
terms of their representations, we wish to show that for all
integers n ≥ 0,
P n ↔ P’n .
(i)
Of course, this can be shown by using the previously obtained
2
result Pn → <n > in conjunction with a direct proof of the
2
fact that P’n → <n >.
But we will prove the equivalence of
the programs by verifying, in effect, that their differing
parts do the same work when the programs are executed.
differing parts are represented by the obs h and h’.
These
If we can
show that for all integers n ≥ 0,
h N n 0 ↔ h’N n 0
(ii)
(where N ≡ j(Axy:I), defined in the present example), then (i)
is demonstrated as follows.
From the previous example, part
(d), we know that for all n ≥ 0,
120
Pn → h(j(Axy:I))n 0 I ≡ hNn 0 I .
But, using the definitions of the present example, we also have
P’n ≡ k’IIn
→ a(b(h’(j(Axy:I))))ΩΩIn
→ b(h’(j(Axy:I)))nΩI
→ h’(j(Axy:I))n 0I ≡ h’Nn 0I .
Hence, it follows from (ii) that Pn ↔ P’n .
It remains to verify (ii).
From (v) in the previous
example, we have for all integers n ≥ 0,
2
h N n 0 → N n n
.
So (ii) would follow if we can also prove
2
h’ N n 0 → N n n
.
(iii)
To outline the proof of (iii), we simply state the sequence of
reduction relations leading to it.
2
N n n
(1)
L i n i
2
, if i = n ,
→
L i+l n (i+1)
2
, if i ≠ n .
(2)
L 0 n 0 → L i n i2,
for 0 ≤ i ≤ n .
(3)
L 0 n 0 → N n n2,
for n ≥ 0 .
(4)
h’φ n 0 → N n n2 ,
for n ≥ 0 .
The treatment of designational expressions and switches is
omitted, except for an example which should suffice to indicate
121
how these may be represented as obs.
In the schematic program
below, b and c denote Boolean, and e and f, arithmetic
expressions.
It is assumed that the omitted statements
indicated by ellipses do not contain any declarations.
begin integer x;
M: ...
begin integer y;
...
begin integer z;
switch P := N, if b then P [e] else L, M;
...
N: ...
begin integer w;
...
goto if c then N else P [f];
end w;
end z;
L: ...
end y
end
The representations of the switch and goto statements in
the above program are, respectively,
122
{P } ≡
<{N},{b}(Azyx:{P}(elem
{e}3)zyx)(Az:{L}),Azy:{M}>,
and
Aφwzyx:{c}(Awzy:{M})(Aw:{P}(elem {f}3)).
(Cf. Section 3.11.) Note that in the above two formulas 3, {e},
and {f} are to be natural number representations.
CHAPTER 5
PROCEDURES
5.1
F-procedures
We use the term F-procedure to denote a type procedure
without any side effects.
In particular, an F-procedure is a
procedure in which
(1)
the procedure name is typed,
(2)
all parameters are called by value,
(3)
no global variables are modified,
(4)
no jumps are made outside the procedure body,
(5)
no procedures are used other than F-procedures.
Because of the above restrictions, the representation of
F-procedures is much simpler than that of general procedures.
Since many procedures encountered in programs are truly
F-procedures, it seems useful to deal with them as a special
case.
For the moment, let us consider only the F-procedures
which do not involve global variables at all.
For these, the
environment of the declaration is immaterial.
Let f be an F-
procedure and p1,...,pn be its parameters.
We wish to
represent f in such a manner that for all expressions e1,...,en
{f}{e1}...{en} → {f(e1,...,en)} .
123
(i)
124
Such a representation is accomplished as follows:
We use a variable
to denote the F-procedure value; that is,
π
all assignments to
f
are represented as if made to π.
Further, we represent the statement S constituting the body of
f by taking its environment to be (π,p1,...,pn).
with an arbitrary value of
Now, starting
π, and the values ei of pi , the
execution of S has the effect of assigning the value
f(e1,...,en) to π, and certain values to pi which are
irrelevant to the result; say, we have
{S}φ π {e1}...{en} → φ {f(e1,...,en)}p1...pn .
To obtain (i) from (ii), we may initialize
π
(ii)
with Ω, and
choose the ob Aφp1...pn:π for φ and {S}φπ for {f}.
Thus we
adopt the following
(1-1) Representation Rule.
{F-procedure f(p1,...,pn) with body S}
≡ {S}(π,p1,...,pn)(Aπp1...pn:π)Ω
It should be pointed out that a label appearing in the
body of an F-procedure is to be represented as the part of the
F-procedure (not the program) that follows the label.
Example.
The following is an F-procedure; hence (1-1) is
applicable.
125
integer procedure mod(x,y);
value x,y; integer x,y;
begin integer q;
q := x+y;
a ≡ Aφqπxy:φ(+xy)πxy
mod := x-y×q
b ≡ Aφqπxy:φq(-x(×yq)xy
end q;
c ≡ Aφ:a(b(Aq:φ))Ω
mod ≡ c(Aπxy:π)Ω
Example.
Representation of the factorial function.
integer procedure fact(n); value n; integer n;
fact := if n = 0 then 1 else n × fact (n-1);
As the body of this F-procedure consists of a single assignment
statement, we have, by (3.5-1),
{body} ≡ Aφπn:φ((=n0)1(×n(fact(-n1))))n .
Hence, the representation of the F-procedure is given by the
recursively defined ob
fact ≡
{body}(Aπn:π)Ω → An:(=n0)1(×n(fact(-nl))).
A non-recursive definition of the above ob is
fact ≡ Y(Azn:(=n0)1(×n(z(-nl)))).
Finally, it is easy to remove the restriction about global
variables imposed earlier on functions: In case the global
variable values are used (but not, of course, modified) in an
F-procedure, we append the global variables to the actual
126
arguments as if they also were parameters in addition to the
explicitly declared parameters of the F-procedure.
This is
illustrated below.
Example.
begin integer x,y;
-
integer procedure f(n);
value n; integer n;
f := n+x;
a ≡ Aφπnxy:φ(+nx)nxy
...
f ≡ a(Aπnxy:π)Ω
begin integer z;
x := f(y)+z;
Aφzxy:φz(+(fyxy)z)y
...
5.2
Call-by-name, Side-effects
In the previous section, we have described the SK
representation of procedures subject to rather stringent
conditions.
We will now show how the representations can be
extended to more general procedures, allowing call-by-name, the
modification of global variables, and side effects.
However,
we limit ourselves here to considering the formal parameters of
the type integer and label only.
The extension of the model to
include real and Boolean parameters is trivial.
In ALGOL 60, a procedure call is intended to have the
effect of an appropriately modified copy of the procedure body
[27].
The modification in the case of call-by-name consists in
replacing each instance of a called-by-name formal parameter by
127
the corresponding actual parameter.
(It is understood that any
name conflicts between the variables appearing in the actual
parameter expressions and the local variables of the procedure
are to be first removed by renaming the latter variables.)
Instead of performing such symbolic substitution, however,
which would require keeping procedures in text form at the
execution time, most ALGOL compilers accomplish the same effect
by treating formal parameter references in procedures as calls
on special “parameter procedures” generated from actual
parameters [30].
As a result, if an operation refers to a
formal parameter during the execution of a procedure, then the
procedure execution is suspended to evaluate the corresponding
actual parameter in the environment of the procedure calling
statement, and then the procedure execution is resumed using
the thus-acquired value in the operation.
Of course, depending
upon the type and use of a parameter, the actual parameter
evaluation may yield a value (e.g., an arithmetic or Boolean
quantity when the formal parameter is an operand in an
expression) or a name (e.g., the address of a variable when the
formal parameter appears to the left of an assignment
statement).
Our SK interpretation is based on a similar idea.
But we are able to avoid the notion of address, and work
exclusively with values, by making use of a number of different
“parameter procedures” for different operations performed with
the same parameter; namely, the evaluation of actual parameter
expressions, making assignments to the variables provided as
128
actual parameters, and jump to an actual label.
5.3.
Integer Parameters
In the absence of procedures we were able to express each
statement in a program as a function which had for its
arguments the variable φ, denoting the program remainder (that
is, the part of the program following the statement), and the
variables constituting the environment of the statement.
Clearly the representation of a statement S in a procedure body
would involve two sets of program remainders and environments - namely, one set for S itself and one for the statement, say
T, that calls the procedure.
The program remainder of T
corresponds to the familiar “return” address or label for the
procedure call.
Now, any formal parameter instances in S give
rise to actual parameter evaluations in the environment of T,
but after the evaluation the control must eventually transfer
back to S.
Hence the representation of parameter evaluation
also involves the two sets of environments and program
remainders; but this time the program remainder of S serves as
the return address.
We will use the variable ρ to indicate the
program remainder at the return point and φ, as usual, for the
program remainder at the current point.
We have so far represented, and will continue to
represent, each program variable by a single indeterminate.
The representation of an assignment statement may be
129
conceived as “binding” the indeterminate representing the
variable appearing at the left-hand side to the representation
of the right-hand expression.
1
In general, the indeterminates
representing program variables are “bound” at any time to the
current values of the corresponding program variables.
With
each called-by-value formal parameter we similarly need to
associate a single indeterminate, bound to the current “value”
of the parameter at any time.
However, we need to carry more
information with a called-by-name formal parameter; depending
on the type and use of a parameter we shall associate a number
of indeterminates with it.
For each called-by-name formal
parameter of type integer, we require three indeterminates best
thought of as being bound, respectively, to the “value”
associated with it and to the “parameter procedures” for
evaluating it and making assignments to it.
If
p
is an
integer parameter, then these three indeterminates will be
usually denoted by p, pε , and pα.
label will be discussed later.)
(The parameter of type
The environment of a statement
in a procedure body will contain the variables corresponding to
all of the above-mentioned indeterminates; specifically, it
will consist of the following in the given order:
1 The present descriptive use of “binding” and “bound” has
no connection with the terms defined at the beginning of
Section 2.3.
130
(a)
variables local to the procedure,
(b)
ρ, the “return” variable,
(c)
variables representing the formal parameters,
(d)
variables global to the procedure.
Next, let us turn to the procedure call.
Associated with
each called-by-name actual parameter p of type integer, and
individual to each procedure call, is an ob that represents the
“parameter procedure” for its evaluation.
In case p is a
program variable (rather than an expression), there is also
another ob which represents the “parameter procedure” to effect
the assignments to p called for in the procedure.
These obs,
referred to as “actual evaluation” and “actual assignment”
operators, are denoted
a
and
εp
a
α p , respectively, with
further distinguishing marks added when more than one procedure
call is involved.
Last, let us consider the procedure declaration.
Associated with each called-by-name formal parameter of type
integer, and unique to each environment within the procedure
body, are two obs which represent the calls on the “actual
evaluation” and “actual assignment” parameter procedures
mentioned above.
For convenience, these obs are referred to as
“formal evaluation” and “formal assignment” operators, and are
f
usually denoted ε p
and
f
α p , where p is the formal parameter,
with further distinguishing marks added if more than one
environment is involved.
If, in a statement in a procedure
131
body, a formal parameter appears as an operand of an
expression, the statement will be represented as if preceded by
a formal evaluation; likewise, if a formal parameter occurs at
the left-hand side of an assignment statement, that statement
will be represented as if immediately followed by a formal
assignment.
The above ideas will now be illustrated by means of a
very simple example in which the declaration and the call of a
procedure have the same environment.
begin integer y;
procedure P(x); integer x; x := x+2;
y := 1;
P(y)
end
The body of the above procedure consists of a single
statement, and that statement needs to be both preceded by a
formal evaluation and followed by a formal assignment.
Thus,
it is represented by the compound
f
f
Aφ: ε x (a(α x φ)) ≡ b ,
say, where a is the representation of x := x+2 as an ordinary
assignment statement.
Since there are no local variables in
the procedure, the environment of this latter statement
consists of the following:
ρ
the “return” variable,
xε
the “parameter evaluation” variable,
132
xα
the “parameter assignment” variable,
x
the “parameter” variable, and
y
the global variable
.
Thus we can write
a ≡ Aφρxεxαxy: φρxεxα(+x2)y .
Now, as the variable
xε is bound to the actual evaluation
operator, and the formal evaluation consists of just an
application of this ob, we define
f
ε x to be
Aφρxεxαxy: xερφxεxαxy
,
or more simply,
Aφρxεxαx: xερφxεxαx
.
Note the interchange of φ and ρ above; this signifies that the
program remainder at the return point of procedure call becomes
the current program remainder during parameter evaluation, and
vice versa.
In a similar manner, we define
f
α x ≡ Aφρxεxαx: xαρφxεxαx
.
(In general, the global variables of the procedure need not
appear in the formal evaluation and assignment operators.)
The whole procedure may be represented by
P ≡ b(Aρxεxαx:ρ)
which displays the effect that once the procedure execution is
over, (after the application of b), only the return variable is
retained, and the other variables, namely, the ones connected
with parameters, are deleted from the environment.
Next, let us look at the procedure call.
There is only
133
one call-by-name actual parameter of type integer in this
a
statement.
So we need to define two obs ε x
actual evaluation and assignment operators.
and
a
α x , the
These serve
essentially as the fictitious assignment statements x:=y and
y:=x (in the environment of the procedure call), respectively,
and thus can be defined by
a
,
a
.
ε x ≡ Aφρxεxαxy: ρφxεxαyy
α x ≡ Aφρxεxαxy: ρφxεxαxx
Again the interchange of φ and ρ is needed to represent the
fact that after evaluating the actual parameter in the
environment of the procedure calling statement, the control
passes back to the procedure body.
2
The purpose of the procedure calling statement itself is
three-fold:
(a)
to extend the environment from (y) to (xε,xα,x,y)
(b)
to initialize the added variables; that is,
substitute
a
a
ε x for xε, α x for xα, and, by convention,
Ω for x.
2
It should not be difficult to see that coroutines can be
represented by using the same idea, as follows: the
“remainder” of each coroutine may be represented by a
different variable. The coroutine calls are then representable by the obs which simply permute these variables to
bring the remainder of the called coroutine in front. We
will soon see how we can also account for the private
variables of a coroutine by “covering” them when the control
passes out of it and “uncovering” them on return.
134
(c)
to apply P before the rest of the program; that is,
substitute Pφ for φ.
Consequently, the statement P(y) above may be represented by
the ob
a
a
(Axεxαx: (Aφy: Pφxεxαxy))ε x α x Ω
,
or, more simply, by
a
a
Aφy: P φ ε x α x Ω y
.
Putting together the representations obtained piecemeal
above, and adding the ones for the assignment and the block, we
can now complete the representation of the program:
Example.
begin integer y;
procedure P(x); integer x;
f
≡ Aφρxεxαx: xερφxεxαx
αx
f
≡ Aφρxεxαx: xαρφxεxαx
a
≡ Aφρxεxαxy: φρxεxα(+x2)y
b
≡ Aφ: ε x (a(α x φ))
P
≡ b(Aρxεxαx:ρ)
y := 1;
c
≡ Aφy: φl
P(y)
d
≡ Aφy: Pφε x α x Ωy
εx
x := x+2;
end
f
f
a
a
εx
a
≡ Aφρxεxαxy: ρφxεxαyy
αx
a
≡ Aφρxεxαxy: ρφxεxαxx
e
≡ Aφ:c(d(Ay:φ))Ω
{prog }
≡ eII
135
Next, let us consider the SK representation of type
procedures in which a value is associated with the procedure
identifier.
In this case we will use an additional variable π
to denote the procedure value in representing the statements of
the procedure body.
The representations are otherwise similar
to those for the untyped procedures discussed above.
A
statement in which the function designator of a procedure is
used as an operand of an expression will be represented as if
it were compounded of two statements -- the first a procedure
call to obtain the value of the procedure, and the second using
that value in the expression.
The representation of a type procedure is shown in the
following example, which also illustrates the treatment of
call-by-value in our present scheme of procedure
representation.
(Some explanation follows the program.)
Example.
begin integer u,v;
integer procedure P(x,y); integer x,y; value y;
f
ε x ≡ Aφρπxεxαxy:xερφπxεxαxy
f
α x ≡ Aφρπxεxαx:xαρφπxεxαxy
begin
P := x-y;
x := y
a
≡ Aφρπxεxαxyuv:φρ(-xy)xεxαxyuv
b
≡ Aφ:ε x (aφ)
c
≡ Aφρπxεxαxyuv:φρπxεxαyyuv
d
≡ Aφ:c(α x φ)
f
f
136
end compound
e
≡ Aφ:b(dφ)
end P;
P
≡ e(Aρπxεxαxy:ρπ)
u:=v:=3;
f
≡ Aφuv:φ3 3
u:=P(v,u+1) + u;
g
≡ Aφuv:PφΩε x α x Ω(+ul)uv
end
a
a
εx
a
≡ Aφρπxεxαxyuv:ρφπxεxαvyuv
αx
a
≡ Aφρπxεxαxyuv:ρφπxεxαxyux
h
≡ Aφπuv:φ(+πu)v
k
≡ Aφ:g(hφ)
m
≡ Aφ:f(k(Auv:φ))ΩΩ
{prog } ≡ mII
The environment of the statements in the procedure above
consists of eight variables: the return variable ρ, the
procedure value variable π, the three variables xε, xα, and x
for the called-by-name parameter x, the single called-by-value
parameter variable y, and finally the two global variables u
and v.
Of these, the four parameter variables are effectively
discarded at the end of the procedure body execution by the
component (Aρπxεxαxy:ρπ) of P above.
The procedure call is
represented as the compound of two statements f and g: f
computes π, the procedure value, and g makes use of this in the
assignment statement.
In both previous examples, the environment of the
procedure declaration and the procedure call are the same.
In
the general case, these environments may be different; this is
so, for example, when a procedure call takes place in a block
enclosed by the block that declares the procedure.
When this
137
happens, there arises the problem of “covering” the local
variables of the calling point whose scopes do not include the
procedure declaration.
Of course, the covering must be such
that the variables may be “uncovered” on return to the calling
point.
Notice the contrast with jumps in which the variables
that do not have valid declarations at the jump label are
simply discarded permanently.
Covering is also needed in
specifying the formal evaluation and assignment operators for
use with statements inside a block in a procedure body, since
in this case, again, the variables local to the procedure body
are invisible at the calling point.
The following example shows a way of covering the
nonoverlapping parts of the environment, in order to overcome
the environment conflict problem.
(See explanations below.)
Example.
begin integer x;
procedure P(y);integer y;
begin integer z;
f
ε y ≡ Aφzρyεyαy:ρyε(Aψ:ψφz)yεyαy
f
α y ≡ Aφzρyεyαy:ρyα(Aψ:ψφz)yεyαy
z := y+3;
a ≡ Aφzρyεyαyx:φ(+y3)ρyεyαyx
f
b ≡ Aφ:ε y (aφ)
end block
c ≡ Aφ:b(Az:φ)Ω
138
end P;
P ≡ c(Aρyεyαy:ρI)
begin integer u;
a
P(u+x);
d ≡ Aφux:P(Aψ:ψφz)ε y ΩΩx
a
...
ε y ≡ Aφuρyεyαy:ρI(Aψ:ψφz)yεyα(+ux)x
end
end
In representing the procedure call in the above example,
(Aψ:ψφz) is passed as the return point argument instead of φ,
thus covering u.
The application of (Aψ:ψφz) to any ob has the
effect of uncovering u and restoring the environment; e.g., in
f
ε y the application is made to yε, and in P, to I.
Note that in
the representation of the procedure call, namely, d, we have
a
used Ω for what would otherwise have been α y ; this is so,
because no assignment can be made to the particular actual
parameter in this case.
The evaluation and assignment operators, both formal and
actual, have been defined above slightly differently than in
the two previous examples in which covering was not required.
These two examples are worked out once again so as to make the
treatment uniform, whether or not covering is needed in a
particular case.
139
Example.
begin integer y;
procedure P(x); integer x;
f
ε x ≡ Aφρxεxαx:ρxε(Aψ:ψφ)xεxαx
f
α x ≡ Aφρxεxαx:ρxα(Aψ:ψφ)xεxαx
x := x+2;
a
≡ Aφρxεxαxy:φρxεxα(+x2)y
b
≡ Aφ:ε x (a(α x φ))
P
≡ b(Aρxεxαx:ρI)
y := 1;
c
≡ Aφy:φl
P(y)
d
≡ Aφy:P(Aψ:ψφ)ε x α x Ωy
f
f
a
a
a
ε x ≡ Aφρxεxαxy:ρI(Aψ:ψφ)xεxαyy
a
α x ≡ Aφρxεxαxy:ρI(Aψ:ψφ)xεxαxx
end
e
{prog }
≡ Aφ:c(d(Ay:φ))Ω
≡ eII
Example.
begin integer u,v;
integer procedure P(x,y); integer x,y; value y;
f
ε x ≡ Aφρπxεxαxy:ρxε(Aψ:ψφ)πxεxαxy
f
α x ≡ Aφρπxεxαx:ρxα(Aψ:ψφ)πxεxαxy
begin
P := x-y;
a
≡ Aφρπxεxαxyuv:φρ(-xy)xεxαxyuv
f
b ≡ Aφ:ε x (aφ)
x := y
c ≡ Aφρπxεxαxyuv:φρπxεxαyyuv
f
d ≡ Aφ:c(α x φ)
140
end compound
e ≡ Aφ:b(dφ)
end P;
P ≡ e(Aρπxεxαxy:ρIπ)
u := v := 3;
f ≡ Aφuv:φ3 3
u := P(v,u+1)+u;
g ≡ Aφuv:P(Aψ:ψφ)Ωε x α x Ω(+ul)uv
a
a
a
ε x ≡ Aφρπxεxαxyuv:ρI(Aψ:ψφ)πxεxαvyuv
a
α x ≡ Aφρπxεxαxyuv:ρI(Aψ:ψφ)πxεxαxyux
h ≡ Aφπuv:φ(+πu)v
k ≡ Aφ:g(hφ)
end
l ≡ Aφ:f(k(Auv:φ))ΩΩ
{prog } ≡ lII
For subscripted variables occurring as actual parameters,
the actual evaluation and assignment operators are again chosen
so as to represent the fictitious assignments between the
formal and actual parameter variables.
But now this involves
the obs elem and replace introduced in the discussion of arrays
(Section 3.11).
We will simply illustrate the representation
by means of an example.
(The statements denoted by ellipses
are assumed not to contain any declarations.)
Example.
begin integer n;
...
begin integer array x [l:n];
procedure P(u,v); integer u,v;
141
begin
...
end P;
begin integer y;
...
P(y,x [y])
end
end
end
For the above program, the representation of the procedure
calling statement P(y,x [y]) is the ob
a
a
a
a
Aφyxn:P(Aψ:ψφy)ε u α u Ωε v α v Ωxn,
where
a
ε u ≡ Aφyρuεuαuvεvαvxn:ρI(Aψ:ψφy)uεuαyvεvαvxn,
a
α u ≡ Aφyρuεuαuvεvαvxn:ρI(Aψ:ψφu)uεuαuvεvαvxn,
a
ε v ≡ Aφyρuεuαuvεvαvxn:ρI(Aψ:ψφy)uεuαuvεvα(x(elem yn)xn,
a
α v ≡ Aφyρuεuαuvεvαvxn:ρI(Aψ:ψφy)uεuαuvεvαv(x(replace ynv)n.
A procedure body may contain a procedure call, possibly a
recursive one, in which the formal parameters are used in
actual parameter expressions.
And the parameters of the nested
call may themselves be called by name.
The representation in
such a case requires the covering of all the variables
associated with the procedure body, including the local
variables, the return variable, and the parameter variables.
142
This is illustrated below.
Example.
begin integer x;
procedure P(y,n); integer y,n; value n;
begin
...
end P;
procedure Q(z); integer z;
begin integer w;
P(z,x);
...
end Q;
...
end
If the representation of the body of the procedure P is a,
then the representation of P itself is
P ≡ a(Aρyεyαyn:ρI) .
The representation of the statement P(z,x) is
f
Aφ:ε z (bφ) ,
f
where ε z is the formal evaluation operator for z in Q, and b
represents the call on P, as follows:
b ≡ Aφwρzεzαz x: P(Aψ:ψφwρzεzαz)ε
a a
y α y Ωx
x ,
a
ε y ≡ Aφwρzεzαz ρ1yεyαy x: ρ1I(Aψ:ψφwρzεzαz)yεyαz x ,
a
α y ≡ Aφwρzεzαz ρ1yεyαy x: ρ1I(Aψ:ψφwρzεzαz)yεyαy x .
143
The next example illustrates the representation of a
procedure calling statement in which an actual parameter itself
consists of a call on a procedure.
Example.
begin integer x;
procedure P(r,s); integer r,s; begin ... end P;
procedure Q(t); integer t; begin ... end Q;
begin integer y;
...
P(x,Q(y));
end
end
Because the second actual parameter, Q(y), in the above
procedure calling statement P(x,Q(y)) does not require an
3
assignment operator, the latter statement is represented by
the ob
a
a
a
Aφyx:P(Aψ:ψφy)ε r α r Ωε s ΩΩx .
The first actual parameter, x, poses no problem other than the
covering of the variable y not visible to the procedure
declaration of P; hence, we define
a
ε r ≡ Aφyρrεrαrsεsαsx:ρI(Aψ:ψφy)rεrαxsεsαsx ,
a
α r ≡ Aφyρrεrαrsεsαsx:ρI(Aψ:ψφy)rεrαrsεsαsr .
3
As explained earlier, an assignment operator is required for
those actual parameters which consist of a single program
variable.
144
For the second actual parameter, Q(y), things are
slightly more complex.
(Note, however, that only an evaluation
operator is needed in this case; the assignment operator is
undefined.) First, we have to provide for a call on Q -- which
requires covering all the variables associated with the call on
P -- with the following actual evaluation and assignment
operators:
a
ε t ≡ Aφyρ rεrαr sεsαs ρ1πtεtαtx:ρ1I(Aψ:ψφyρrεrαrsεsαs)πtεtαyx
a
α t ≡ Aφyρ rεrαr sεsαs ρ1πtεtαtx:ρ1I(Aψ:ψφtρrεrαrsεsαs)πtεtαtx
a
Now, ε s is defined in terms of a call on Q, followed by an
assignment of the resulting value to s, as follows:
a
a
a ≡ Aφyρ rεrαr sεsαs x:Q(Aψ:ψφyρrεrαrsεsαs)Ωε tα tΩx ,
b ≡ Aφyρ rεrαr sεsαs πx:ρI(Aψ:ψφy)rεrαrsεsαπx ,
a
ε s ≡ Aφ:a(bφ) .
145
5.4
Label parameters
The representation of label parameters is actually much
simpler than of the integer variety.
The reason is that two
different operations, evaluation and assignment, are possible
with the latter type; in addition, the value of the parameter
at any time has to be carried also along within the
representation.
In the case of a label parameter, the only
possible actual operation is a jump to it.
Thus, with each
formal label parameter, p, we need to associate only one
variable, denoted by pγ, which is to be bound to the operator
for effecting the actual goto operation.
(The variable pγ is,
of course, an element of the environment of the procedure
body.) Next, associated with each actual label parameter, and
individual to each procedure call, is an ob that represents the
parameter procedure to effect the jump to the actual label.
For a parameter p, this “actual goto” operator is denoted by
a
γ p , with further distinguishing marks added when more than one
procedure call is involved.
Last, associated with each formal
label parameter, and unique to each environment within the
procedure body, is an ob, the “formal goto” operator, that
represents a call on the actual parameter procedure, that is,
an application of the actual goto operator; the formal goto
f
operator for the parameter p is denoted γ p , again with further
distinguishing marks added if more than one environment is
involved.
For anyone who has followed the previous treatment of jumps
146
(Section 4.3) and procedures with integer parameters (Section
5.3), the example below should suffice to explain how
to represent label parameters.
Example
begin integer q;
procedure R(v); label v;
goto v;
f
a ≡ γ v ≡ Aφρvγ: ρvγ(Aψ:ψφ)vγ
R ≡ a(Aρvγ:ρI)
begin integer r;
procedure P(x,z); integer x; label z;
f
ε x ≡ Aφρxεxαxzγ:ρxε(Aψ:ψφ)xεxαxzγ
f
α x ≡ Aφρxεxαxzγ:ρxα(Aψ:ψφ)xεxαxzγ
f
γ z ≡ Aφρxεxαxzγ:ρzγ(Aψ:ψφ)xεxαxzγ
R(z);
a
b ≡ Aφρxεxαxzγrq:R(Aψ:ψφρxεxαxzγr)γ v q
a
f
γ v ≡ Aφρxεxαxzγrρ1vγq:γ z φρxεxαxzγrq
begin integer s,t;
P(t,L)
a
a
a
c ≡ Aφstrq:P(Aψ:ψφρst)ε x α x Ωγ z rq
a
ε x ≡ Aφstρxεxαxzγrq:
ρI(Aψ:ψφst)xεxαtzγrq
a
αx
a
≡ Aφstρxεxαxzγrq:ρI(Aψ:ψφsx)xεxαxzγrq
γ z ≡ Aφstρxεxαxzγrq: L r q
end;
L: ...
end
end
CHAPTER 6
CONCLUSION
In this dissertation, we have presented a combinatory
logic (or, equivalently, lambda-calculus) model of programming
languages.
Since a number of programming language models based
on the same calculi have already appeared in the literature
[5,11,16,17,18,28,31,36], a comparison of our model with others
is in order.
1.
Our model does not introduce any imperative or
otherwise foreign notions to the lambda-calculus.
This is in
contrast to Landin [17], in which the imperative features of
programming languages are accounted for by ad hoc extensions of
the lambda-calculus.
We find that the calculus, in its purity,
suffices as a natural model of programming languages.
By not
making any additions to the calculus, we have the guarantee
that all its properties, in particular, the consistency and the
Church-Rosser property, are valid in our model, For example,
even when a program requires a fixed order of execution, the
normal form obtained by evaluating the program representation
in any order, whatsoever, represents the program result
correctly.
2. In our model, programs are translated into lambdaexpressions, not interpreted by a lambda-calculus interpreter
(Reynolds [31]).
Thus, programming semantics is completely
reduced to the lambda-calculus semantics, but without
147
148
commitment to any particular view of the latter.
Also, all
lambda-expression transformations are applicable to program
representations.
3.
We model assignments by the substitution operation
of the lambda-calculus.
Consequently, the notions of memory,
address, and fetch and store operations do not enter our
model in any explicit manner (Stratchey [36], Reynolds [31]).
4.
We represent high-level programming language
constructs directly, not in terms of the representations of
the machine level operations (Orgass-Fitch [28]) of the
compiled code.
5.
language.
Our model potentially spans the full ALGOL 60
It is also applicable to a number of other
advanced programming features, such as collateral statements,
the use of labels and procedures as assignable values,
coroutines, etc.
6.
As a matter of opinion, it seems that our
representations are much simpler and clearer than the ones
given in other models.
We have described the model informally, and only for a
representative set of programming language constructs.
But
we have provided enough motivating details and illustrations
to, hopefully, convey the method and suggest its extension to
other programming features.
Our explanations, we believe,
are quite adequate for the detailed construction of an
effective procedure, say, in the form of a compiler, to
149
translate ALGOL 60 programs into lambda-expressions.
An immediate application of our model is in a functional
(as opposed to computational) semantic definition of high-level
programming languages, as the combinatory interpretations of
the individual programming constructs can themselves be taken
as the semantic specification of the constructs.
Of more
interest, however, is the potential of the present model in
studying the properties of programs -- such as, convergence,
correctness, and equivalence -- and in performing useful
program transformations -- such as program simplification
(source code level) and optimization (compiled code level).
Since we describe a program as a lambda-expression or a
combinatory object, the above-described applications
essentially reduce to transformations within the respective
calculi.
The possibilities of some of these applications have
been indicated by examples.
In the case of loop-free programs,
these applications most often involve straightforward lambdacalculus reduction.
For the programs containing loops, our
proofs of correctness and equivalence are rather ad hoc; the
development of systematic methods to deal with these
applications warrants further research.
REFERENCES
1.
Abdali, S. K., A simple lambda-calculus model of
programming languages, AEC R & D Report cOO-3077-28,
Courant Inst. Math. Sci., New York Univ. (July 1973).
2.
deBakker, J. W., Formal Definition of Programming
Languages, Mathematisch Centrum, Amsterdam (1967).
3.
______________, Recursive Procedures, Mathematical Center,
Amsterdam (1972).
4.
Böhm, C., The CUCH as a formal and description language,
in Formal Language Description Languages ed. Steel, T.
B.)., North-Holland, Amsterdam (1966), 179—197.
5.
Burstall, R. M., Semantics of assignment, in Machine
Intelligence 2 (ed. Dale, E., and Michie, D.), Oliver and
Boyd, Edinburgh (1967), 3-20.
6.
_______________, Formal description of program structure
and semantics in first-order logic, in Machine
Intelligence 5 (ed. Meltzer, B., and Michie, D.),
Edinburgh Univ. Press, Edinburgh (1970), 79-98.
7.
Cadiou, J. M. and Manna, Z., Recursive definition of
partial functions and their computations, SIGPLAN Notices
7, 1 (Jan. 1972), 58—65.
8.
Church, A., The Calculi of Lambda-Conversion, Princeton
Univ. Press, Princeton, N. J. (1941).
150
151
9.
Curry, H. B., and Feys, R., Combinatory Logic, Vol. I,
North-Holland, Amsterdam (1956).
10.
Floyd, R. W., Assigning meanings to programs, Proc. Symp.
in Appl. Math., Amer. Math. Soc. 19 (1967), 19—32.
11.
Henderson, P., Derived semantics for programming
languages, Comm. ACM 15, 11 (Nov. 1972), 967—973.
12.
Hoare, C. A. R., An axiomatic basis for computer
programming, Comm. ACM 12, 10 (Oct. 1969), 576—580,583.
13.
Igarashi, S., On the equivalence of programs represented
by ALGOL-like statements, Report of Computer Center, Univ.
of Tokyo 1, 1 (1968), 103-118.
14.
Kleene, S. C., Introduction to Metamathematics, van
Nostrand, Princeton, N. J. (1950).
15.
Knuth, D. E., Examples of formal semantics, in Symp. on
Semantics of Algorithmic Languages (ed. Engeler, E.),
Springer-Verlag (1971), 212—235.
16.
Landin, P. J., The mechanical evaluation of expressions,
Computer J. 6, 4 (Jan. 1964), 308—322.
17.
_______________, A correspondence between ALGOL 60 and
Church’s lambda-notation, Comm. ACM 8, 2-3 (Feb., Mar.
1965), 89—101, 158—165.
18.
Ledgard, H. F., A model of type-checking, Comm. ACM 15, 11
(Nov. 1972) 956—966.
152
19.
Lee, J. A. N., Computer Semantics, van Nostrand Reinhold,
New York (1972).
20.
London, R. L., The current state of proving programs
correct, Proc. ACM Annual Conf. (Aug. 1972), 39-46.
21.
Lucas, P., Lauer, P., and Stigleitner, H., Method and
notation for the formal definition of programming
languages, Report TR 25.087, IBM Laboratory, Vienna
(1968).
22.
Manna, Z., and Vuillemin, J., Fixpoint approach to the
theory of computation, Comm. ACM 15, 7 (July 1972), 528—
536.
23.
McCarthy, J., A basis for a mathematical theory of
programming, in Computer Programming and Formal Systems
(ed. Braffort, P., and Hirshberg, D.), North-Holland,
Amsterdam, (1963), 33—70.
24.
McGowan, C., Correctness results for lambda-calculus
interpreters, Ph.D. thesis, Comp. Sci. Dept., Cornell
Univ. (1971).
25.
Milner, R., Implementation and application of Scott’s
logic for computable functions, SIGPLAN Notices 7, 1
(Jan. 1972), 1—6.
26.
Morris, J. H., Lambda-calculus models of programming
languages, Ph.D. thesis, Project MAC, MIT, MAC-TR-57
(Dec. 1968).
27.
Naur, P. et al., Revised report on the algorithmic
language ALGOL 60, Comm. ACM 6, 1 (Jan. 1963), 1-17.
153
28.
Orgass, R. J., and Fitch, F. B, A theory of programming
languages, Studium Generale 22 (1969), 113—136.
29.
Petznick, G. W., Combinatory programming, Ph.D. thesis,
Comp. Sci. Dept., Univ. of Wisconsin, Madison (1970).
30,
Randell, B., and Russel, L. J., ALGOL 60 Implementation,
Academic Press, New York (1964).
31.
Reynolds, J. C., Definitional interpreters for higherorder programming languages, Proc. ACM Annual Conf. (Aug.
1972), 717—740.
32.
Rosen, B. K., Tree-manipulating systems and Church-Rosser
theorems, J. ACM 20, 1 (Jan. 1973), 160—187.
33.
Rosser, 3. B., Deux Esquisses de Logigue, GauthiersVillars, Paris (1955).
34.
Schönfinkel, M., Über die Bausteine der Mathematischen
Logik, Mathematische Annallen 92 (1924), 305-316.
35.
Scott, D., Lattice theory, data types, and semantics, in
Formal Semantics of Programming Languages (ed. Rustin,
R.), Prentice-Hall, New Jersey (1972), 65—106.
36.
Stratchey, C., Towards a formal semantics, in Formal
Language Description Languages (ed. Steel, T.B.), NorthHolland, Amsterdam (1966), 198-220.
154
37.
Wegner, P., Programming Languages, Information Structures,
and Machine Organization, McGraw-Hill, New York (1968).
38.
van Wijngaarden, et al., Report on the algorithmic
language ALGOL 68, Numerische Math. 14 (1969), 79—218.