49
A type-theoretic approach for program development Wei Li Dept. of Computer Science, Beijing Institute of Aeronautics, Beijing, P.R. China
A paradigm of program development using type theories is given after analyzing some typical examples. In order to carry this approach forward, a language A L T is designed, a linguistic description of a generalized higher order typed lambda calculus with 1I, Y~ types and 11, Y, kinds (supertype). Four examples are given to show how A L T can be used to implement many concepts of software engineering and artificial intelligence, they are intuitionistic logic, Peano arithmetic, approximate reasoning and program transformation. A L T is described formally, using a structural operational approach.
i. I n t r o d u c t i o n
The notion of type is one of the kernel concepts in programming languages. Since Martin-LSf introduced his intuitionistic type theories to computer science, research in type theory and its applications has now entered a new stage. Many important results, such as Calculus of Constructions [6], Isabelle [13] and Edinburgh LF [8] have been emerged rapidly within the area. On the one hand, types structure has been enriched significantly, so that we can specify and implement many high-level concepts of software engineering, such as "asserts", "problems", "rules", "transformations", "strategies" and even "program development process", which are more difficult to deal with using traditional approaches. Many applications have been investigated along this direction, such as [7], and constructing proof editors [1]. All of these efforts herald a new approach in constructing computer-aided tools and program development environments in both software engineering and artificial intelligence. On the other hand, if we study these works carefully, we will find that their type theory is introduced only to serve some special that their type theory is introduced only to serve some special purposes. For example, the type theory given by Martin-LSf is introduced to define intuitionistic (first order) logic under the principle of "propositions as types"; the /7 type and X type are introduced to specify universal and existential quantification, but there are no "kinds" (supertypes) in his theory. (There is hierarchy of universes, such as in Nuprl, but this is not general enough to make it useful like LF.) The Edinburgh LF is introduced to provide a general framework for expressing various logic systems and to construct interactive proof development environments for them under the principle of "judgments as types"; a supertype "kind" is introduced to define high order judgments, but there is no X type. What we need now is to abstract the paradigm of this new approach from those works mentioned above, and to design a new kind of language or tool incorporating the advances within type theory, and to show how those widespread concepts of software engineering and artificial intelligence can be implemented using such a language. Thus the paradigm of this approach is given in Section 2, after analyzing some typical examples concerning type theory. As a contribution to this approach the language ALT is designed, and its abstract
North-Holland Future Generations Computer Systems 6 (1990) 49-63 0376-5075/90/$03.50 © 1990 - Elsevier Science Publishers B.V. (North-Holland)
W. Li / Type-theoretic approach for program development
50
syntax is given in Section 3. Some programming examples in A L T are discussed in Section 4 to show the role of this language in program design. The language is described using structural operational semantics, and a static semantics, dynamic semantics and the interaction between the two are described in Sections 5, 6 and 7.
2..~ paradi~nl of program con,~truclion usin~ t.~pe Ihe<~ries In this section we will give a general paradigm of program development using type theories after analyzing two major examples. Example I. Martin-L6f type theory and intuitionistic logic. In his lecture note, Martin-L6f introduced a type theory to implement intuitionistic (first order) logic. His approach can be summarized by the following steps: (1) Viewing propositions as types. When we state a proposition, for example, "John is a thief", we have actually made a judgment; therefore a proposition can be identified as a judgment. When we say " a proposition is true" we mean that the judgment is formed upon facts (evidences); thus a proposition (judgment) can be viewed as the set of all its evidence, or more precisely as the name of the set of all its evidence. In mathematics, evidence of a proposition is just a proof of that proposition, so a proposition is the set of all its proofs. In computer science, we do not consider general sets, we only deal with constructive sets which are called types. Therefore a proposition is identified as the type of its proofs. (2) Constructing types. We than have to answer what these types are and how to construct them. This is the contents of Martin-L6f's intuitionistic type theory. The types are as follows: let A, B be types, then the types constructed are the product A x B, the sum (disjoint union) A + B, the function space A + B, the infinite product H x : A . B and the infinite sum 2 x : A . B. Each of these types is constructed by some rules (see [12]). (3) Translating propositions into types. The rest is to interpret propositions using types, and this can be done by a simple syntax directed translation [7]. Let o denote the translation, it can be defined recursively as below: (A and B)° = A ° x B° (A or B) ° = A ° + B ° (A ~
B)° = A ° -> B°
(for all x: A- B(x)) ° = H x : A . (BCx)) ° (for some x : A - B(x)) ° = 2 x : A . ( B ( x ) ) ° . (4) We view a proposition as a specification of a program, in other words, the program is viewed as a proof of that proposition. Since the rules of the type theory tell us the relationship between a type and its values (or its proofs) (see [12]), by proving a proposition the program (the proofs) will be constructed automatically. This is the basic idea of Constable's synthesis approach in Nuprl [7]. l'Nample 2. Edinburgh Logical Framework (ELF). The ELF is introduced to provide a general framework for expressing various logics. The approach of ELF can be outlined as follows: (1) Regarding the form of inference rules as types. Any logic system consists of syntactic categories and inference rules. For example, in Peano arithmetic, there are two syntactic categories: the individual expressions (for numbers) and formulae;
W. Li / Type-theoretic approach for program development
51
they can be classified as types, I and 0 respectively, and can be defined recursively using a BNF like notation. Let us now deal with its inference rules. Consider the Double Negation Elimination rule: DNE: - B
'
where D N E is the name of the rule. The meaning of this rule is that for all wff B the truth of B is derived from the truth of -~--~. Let the symbol ~- denote d e r i v a t i o n , / \ 0' : 0 mean " f o r all B of type 0" and true (O) denote the truth of B, the rule D N E should be written as" DNE: / \ ~ :
0. (true(--,--~0) t- true(~)).
In fact, any rule of a logic system can be constructed by two basic forms (in ELF the form of a rule is called a high order judgment): (i) Hypothetical form J1 I- J2, where J1 and J2 are forms of rules. In the case of DNE, it is true (-~-~) t- true(o). The hypothetical form means that J2 is a logical consequence of J1, and it is evident if there exists a function mapping proofs of J1 to proofs of J2. Therefore, if we use (Ji) o to denote the set of all proofs of Ji, i = 1, 2, we can identify J1 ~- J2 as the function space type (J1) ° ~ (J2) °. (i_i) Schematic f o r m / \ x : A . J(x), where J(x) is a form of a rule containing a parameter x of type A. In the case of D N E J(O) is true (--,-~) ~- true(0). The schematic form represents the idea of generality: the form is evident for any object x of type A if there exists a function mapping object x of type A to proofs of J(x). Let J(x) ° denote the set of all proofs of J(x), then the type of this function is H x : A . (J(x)) °, t h u s / \ x : A- J(x) can be identified as H x : A . (J(x)) o. Since the form of any rule of a logic system is constructed by the above two basic forms, it is identified as a type, and the name of that rule is viewed as an element of the type. This type is not empty because the rule exists. For example, D N E is an element of the type HB : 0 . (true(-~-,0) ~ true(B)). (2) Construction types. We use the constant Type to have as values all types, i.e. Type is a supertype called a kind. Since true (O) is the set of all proofs of --,--~0 (see above), true (O) E Type. Therefore true is a function of type 0 --, Type, and written as: true : 0 ~ Type. The type of the hypothetical form -~-~ t-B is: true(--,--dJ) --* true(B). It is easy to see that in ELF one has to deal with three different categories: objects, types and kinds (supertypes). Objects are classified by types, types by kinds. The detailed constructions of these categories can be found in [8]. (3) Translating the forms of rules into types. This is also done by a syntax directed translation o. (B) ° = true(B) (Jl ~- J2)o = J1 ° ~ J2 ° ( / \ ~ : 0. J(B))o = l / ~ : 0 - J ( B ) o From the above two examples we obtain the following paradigm of program developmeiat using type theories: 1. Many concepts of software engineering often occur in pairs, in which one can be viewed as a type and the other is an element of the type. For example, a specification can be viewed as a type and its corresponding programs are elements of that type; an assertion of a piece of program can be regarded as a type and the piece of program is an element of that type; the form of an inference rule of a logic system is viewed as a type and the name of this rule is an element of the type; program development process starts from a specification and goes through a series of more and more detailed versions until a sufficiently efficient program is obtained; each version can be seen as a type, so the development process is also a type, and transformation rules are functions mapping between these versions, etc.
52
W. Li / Type-theoretic approach for program development
2. What these types are and how to construct them effectively is the key work for this approach, therefore we need to build a unified type theory and design a language based on this unified type theory, so that it can be used to implement those widespread concepts mentioned above. 3. A concept (of software engineering or artificial intelligence) can or cannot be interpreted as a type, depending on the semantics of the language. One concept can even be interpreted as different types, and we will get different program development systems. For example, a proposition, say " A and B", is interpreted as type A ° x B o in Example 1, and in Example 2 " a n d " is interpreted as a constructor of type 0 x 0---, 0, where 0 is the type of all wff formulae (see Example 5); thus we get intuitionistic logic in Example 1, and Peano arithmetic in Example 2. 4. To implement a pair of concepts is to find a proper translation, which maps the concepts to types of the language. This may be called concept typification. In this stage, the translations are mainly syntax directed, or say, context free translation; it is likely that the context sensitive translation should be used more often than the context free case. 5. The benefit of this approach is that the work about verification is reduced notably; the reason of this is that program construction and proof (verification) are united together and are the key point of this approach. For example, according to Constable's synthesis, a program can be extracted from proving its specification, so the verification of this program is no longer necessary; using ELF to build a proof editor for a logic system, verifying a given proof becomes checking the type of this proof and it can be done automatically by a type checking algorithm. The remainder of this paper is an attempt to design a language based on a unified type theory. We call it ALT, an Applicative Language with a powerful Type system. In fact, it is a language description of a generalized high-order lambda calculus with /7, 2 types and /7, 2 kinds. It should be mentioned that some of the notations of ALT are similar to Quest [5] but also richer than Quest. We then give some examples to show how the concepts of software engineering and artificial intelligence can be programmed in this language. These examples are intuitionistic logic, Peano arithmetic, approximate reasoning and program transformation. In order to make readers understand the main constructs of the language ALT precisely and to avoid involving too many details of the language, we describe ALT formally using a structural operational approach (see [14] and [10], which allows us to use abstract syntax, and to describe static and dynamic semantics using axioms and rules which are very close to, but more flexible than the formal description of typed lambda calculus (see [9]).
3. Abstract syntax of ALT The language ALT is an applicative language with a powerful polymorphic type system. It contains five basic entities: objects, types and operators, kinds, signatures, and arguments. Objects are classified by types, types by kinds. The abstract syntax of ALT is defined using the following BNF like notation: Objects a := c Ix [fun(S)a [a(D) I (D, a) [bind S = a in b Irecfun(x : A)a [if b the a else e Types and A := C IX [ALL(S)A [SOME(S)A IFUN(S)A [A(D) [BIND S = A IN B I (D, A) IIF b T H E N operators A ELSE B Kinds K .'= TYPE [KALL(S)L IKSOME(S)L Signatures S .'= empty IS, x : A Arguments D .'= empty [D, a. For the above abstract syntax of ALT we have the following explanations: Boolean expressions are ranged over by b. Objects are ranged over by a, e; c ranges over constants and x, y, z indicates object variables; fun(S)a denotes typed lambda abstractions with multi-bounded variables which cannot be type variables, a(D) describes applications. For example, the typed lambda expression \ x : int, y : int- x is represented by fun(x:int, y : i n t ) x in ALT. The term (D, a) describes a tuple whose right most element may depend on the other elements. The term " b i n d S, y : A = a in e" is a generalized form of Martin-Lrf's E operator [12] and Cardelli's bind operator [4]; it splits the tuple a and binds the components to the variables defined in S and y which can be used in the scope e. Thus, the projections of the tuple can be easily defined.
W. Li / Type-theoretic approach for program development
53
Types are ranged over by A, B; C stands for constant types, X, Y, and Z indicate type variables; ALL(S)A is a generalized form of Martin-LiSf's dependent function type; it denotes the type of functions mapping input signature S (multi-variables) into an element of type A, where A may depend on S. SOME(S)A is a generalized form of dependent product type; it denotes the type of tuples consisting of left components which are the variables defined in S and the right most components of type A, where A may depend on the values of the left components. The term FUN(S)A denotes typed lambda abstraction with multi-bounded variables which may included type variables. The term A(D) stands for an application with A being a type term. The term (D, A) denotes a tuple whose the right most component is a type term and may depend on the left components. The term BIND S = Z IN B is similar to the construct defined for objects except that B here is a type term. Kinds are ranged over by K, L, M. TYPE is the kind of all types, i.e. for any type A, we have A : TYPE. The kind KALL(S)L classifies functions f which yield a type f(D) when applied to an argument D determined by the kind of f, e.g. FUN(X : int)int has the kind KAL(X : int)TYPE. The kind KSOME(S)L classifies all tuples with left components being the variables defined in S and the right most component of kind L, where L may depend on the values of the left components. Signatures are ranged over by S. Signatures are used to express bound variables and environments. A simple signature can be x ' A where x is an object variable and A is a type. A compound signature is a sequence of simple signatures. Arguments are ranged over by D, it is introduced to express applications for typed lambda calculus with multi-bounded variables. A simple argument can be an object a, and a compound argument is a sequence of simple arguments. Example 3. Let x be a variable of type int, and even(x) be a function defined already, and consider the term a = if even(x) the 2 else fun(x : int)x. It is easy to see that the type of a is A = IF even(x) THEN int ELSE ALL(x: int)int. Here the value of A depends on the values of x, and the kind of A is TYPE. Finally, we conjecture that ALT contains the type theory given by Martin-Lrf as well as the Edinburgh LF as its subtheory, and we hope that a formal proof about this will be given soon.
4. Examples In this section we discuss some applications of ALT through three examples. Example 4. Intuitionistic logic. As discussed in Example 1, the intuitionistic logic be programmed in ALT using a translation called trans defined as below: Let void be a constant type which denotes the empty set. trans(false) = void trans(not(P)) = ALL(x: trans(P))void trans(P and Q) = SOME(x: trans(P))trans(Q) trans(P = Q) = ALL(x: trans(P))trans(Q)
IN. Li / Type-theoretic approach for program development
54
trans(P ¢* Q) = SOME(z:(ALL(x : trans(P))trans(Q))(ALL(y : trans(Q))trans(P))) trans(for all xl : A1 ..... xn : An.P) = ALL(xl : A1 . . . . . xn: An)trans(P) trans(for some xl : A1 ..... xn : An.P) = SOME(xl : A1 . . . . . xn : An)trans(P). I.~xamplc 5. Constructing proof editors. All types defined in Edinburgh LF are also contained in ALT, so we can build proof editors for various logic systems using ALT in the same way as people of Edinburgh did. For example, Peano Arithmetic can be done as follows: Let I be the type of individuals, and 0 be the type of propositions: I : TYPE 0 : TYPE. The individual expression constructors of Peano Arithmetic are expressed by the following constant objects: 0 :I
succ : ALL(x: I)I
add: ALL(x: I, y: I)I
mlt: ALL(x: I, y : I)I.
The logic connectives of Peano Arithmetic are expressed by: equal : ALL(x : I, y: I)0 not: ALL(x: 0)0 imply: ALL(x: 0, y: 0)0
less : ALL(x: I, y: I)0 and: ALL(x: 0, y: 0)0 or: ALL(x: 0, y: 0)0
for-all: ALL(y: (ALL(x: I)0))0 for-some: ALL(y: (ALL(x: I)0))0. Thus for example, the formula for-all x : I. x = x is represented by: for-all(fun(x: I)(equal(x)(x))). The inference rules of Peano Arithmetic can also be expressed by functions of certain types of ALT. As we discussed in Example 2 true is a constant function of type: true: ALL(x : 0)TYPE. We use type-of(J) to denote the type of the form of a rule J, so type-of is a translation and can be defined recursively as below: type-of(J) = true(p) if J is a single formula type-of(J1 ~- J2) = ALL(x: type-of(J1))type-of(J2) type-of(for-all x: A. J(x)) = ALL(x: A)type-of(J(x)). Using this definition, the type of the rule of double negation is D N E : ALL(p: 0) { ALL(x: true(not(not(p))))true(p) }.
Thus for example, if p is a formula and a is a proof not(not(p)), i.e. a : true(not(not(p))), then DNE(p) (a) is a proof of p. Using this approach [1] many logic systems can be represented by ALT. Fxamplc 6. Approximate reasoning. In this example we try to implement inference rules of approximate reasoning (see [15]). To do so, we should introduce a new constant type LH, whose elements are so called "linguistic hedges": LH = (very, likely, approximate, quite . . . . }. A fuzzy proposition can be obtained by adding these linguistic hedges to a normal proposition. For example, the fuzzy proposition "Hoffmann is very tall' is obtained from the proposition "Hoffmann is tall" by adding "very". Thus the fuzzy process of propositions can be defined by the following function: fuzzy: ALL(x: L H ) ( A L L ( x :0)0)
W. Li / Type-theoretic approach for program development
55
for example, if p denotes "Hoffmann is tall" the term fuzzy(very)(p) is the (fuzzy) proposition "Hoffmann is very tall". Approximate reasoning usually has following form: (Hoffmann is tall) it is likely that Hoffmann is heavy Hoffmann is very tall Hoffmann is quite heavy According to Zadeh's original idea, here "quite" is obtained by two steps of computation, the first step computes the composition of fuzzy relation (very ° likely), where o is a composition operator, and the second step is so called linguistic approximation which finds the best linguistic hedge from LH for (very ° likely). Unfortunately, there is no obvious candidate for the notion of 'best' such approximation. If we abstract away the concrete algorithms about composition of fuzzy relation and linguistic approximation, a formal inference rule of approximate reasoning should be a normal rule with conditions, such as, for some 11,..., lncLH. For example, the elimination rule of implication of fuzzy logic should be written as:
lEE: fuzzy(l)(p) (p) q for some I'~LH. fuzzy(l')(q) If we use \ / x : A to mean for some x of type A, then the rule can be written as: I E F : / \ p , q : 0, 1 : LH.( \ / l ' : Ln.( fuzzy(1)(p) ~- ((p ~- q) ~- fuzzy(l')(q)))). Here we obtain the third basic form of inference rules, the existential form \ / x : A . J(x), where J(x) is a form of a rule containing a parameter x of type A. It is evident if for some x of type A we can construct the proof of J(x). The corresPonding type of this form is ~ x : A- (J(x)) °. Thus the IEF rule can be expressed using a constant function of the following type in ALT: IEF: ALL(p : 0, q : 0, l : LH)( SOME(I' : LH)( ALL(x: true(fuzzy(1)(p))) ALL(y: (ALL(z: true(p))true(q)))true(fuzzy(l')(q))). Example 7. Program transformation. In many research projects, such as CIP [2] and PROSPECTRA, programs are developed by specification and transformation. There are many ways to interpret specifications and transformations by types. In this example, we only consider one of them. Thus a transformation system consists of some syntactic categories and some transformation rules; the categories are specifications of different versions, and transformation rule is a function mapping between specifications. A rule can be written as: sl 8:-S2
if B(sl, S2),
where sl, s2 are specifications, ~ is the name of the rule and B(sl, s2) is called applicability condition. The rule means that if B(sl, s2) is applicable then sl can be replaced by s2. Let $1 be the type of sl, $2 be the type of s2, and we have: $1: TYPE and $2: TYPE. If we use proc(s) to denote the set of all programs satisfying s, then we have: procl(sl) : TYPE procl : S1 ---, TYPE
proc2(s2) : TYPE. proc2: $2 ---, TYPE.
W. Li / Type-theoretic approach for program development
56
L e t / \ s : S mean "for all s of type S", and B ~ J denote that if B is applicable than J, then rule ~ can be rewritten as: 8:/\sl
: $1./\s2:
$2- (B(sl, s2) ~ ( p r o c l ( s l ) F- proc2(s2))).
To represent a transformation rule we need the fourth basic form of inference rules; it is: Conditional form B = J, where J is a rule form. It means that if B is true than J is evident. Let N U L L be a polymorphic null function, and let J o be the type of J, the form B ~ J can be identified as IF B T H E N J o ELSE NULL. To understand the above explanation, let us consider a simple transformation rule: while b do s A: if b then s; while b do s else skip " We have b : 0 (see Example 5) and let S: TYPE be the type of statements, and skip: S _; _: A L L ( s : S , s : S ) S if_then_else_: ALL(b :0, s: S, s : S)S w h i l e d o _ : ALL(b :0, s : S)S. Finally, the rule can be written as: A:ALL(b : 0, s : S) (ALL(x: proc(while b do s) proc(if b then s; while b do s else skip)). After studying the above examples, we hope that readers have already got the flavor of the type-theoretical approach for program developments.
5. A static semantics of ALT For any programming language, we may write invalid programs if we are only given its syntax defined by BNF like notation. For example, the following program does not have any syntactical errors, but it is an invalid program since the variable x is declared twice and the variable y is not specified: program POOR(input, output); var X, X: integer; begin X:=Y+I; end; This example shows that there must be some specifications of the context sensitive requirements for each entity before they are used; in a way, a membership relation between objects and their type (or say well-typed terms) can also be viewed as a context sensitive requirement. These specifications are called static semantics. Programs which satisfy these requirements of the static semantics are called valid or well-formed or well-typed programs. There are several formal methods for expressing static semantics. The structural operational approach employs formal systems, i.e. these requirements are specified by axioms and rules; axioms specify them directly, whereas rules specify them indirectly, in that if the hypotheses of a rule are satisfied then the conclusion of that rule specifies a requirement. To this end, for the static semantics of ALT we introduce: S S S S
- S sig -D = S - K kind -A : K -a :A
to to to to to
mean mean mean mean mean
S is a valid signature D has signature S K is a valid kind A has kind K a has type A.
W. Li / Type-theoretic approach for program development
57
Let ~2 range for an entity of ALT, and we define FV(I2) - the set of free variables occurred in Q. DV($2) - the set of bounded variables used in I2. FV and DV can be defined recursively using the following tables:
Signature DV
empty f~
S, x : A DV(S)U{x}
FV
empty f~
D, a FV(D)UFV(a)
FV
TYPE f~
KALL(S)K FV(S)U(FV(K) \ DV(S))
KSOME(S)K FV(S)U(FV(K) \ DV(S))
FV
X {x}
ALL(S)A FV(S)U(FV(A) \ DV(S))
SOME(S)A FV(S)U(FV(A) \ DV(S))
FV
C {j~}
FUN(S)A FV(S)U(FV(A) \ DV(S))
A(D) FV(A)UFV(D)
(D, A) FV(D)UFV(A)
FV(C)U(FV(B) \ (DV(S), Y})
Arguments
Kinds
Types
FV
B I N D S, Y : K = A I N B
FV
IF b THEN A1 ELSE A2 FV(b)UFV(A1)UFV(A2)
FV
x fun(S)a {f~} FV(S)U(FV(a) \ DV(S))
FV
c {~}
Objects
FV
(D, a) FV(D)U(FV(a)
if b then al else a2 FV(b)UFV(al)UFV(a2)
a(D) FV(a) U FV(D)
bind S, y : A = c in b FV(c)U(FV(b) \ {DV(S), y}) recfun(x : A)a FV(A)U(FV(a) \ (x})
We assume that the type bool is a predefined type of boolean expression, and Sv is defined recursively by the following table: Sv
empty empty
SI, x : A Slv, x
Thus valid entities are defined by the following axioms and rules:
Signature (1) ~ empty sig
(2)
S ~- A: TYPE xcDV(S) ~- S, x:A sig
W. Li / Type-theoretic approach for program development
58
Rule 1 is an axiom. Rule 2 says that if for a given signature S, A is a valid type and x is not used in S, then S, x : A is a valid signature.
Kinds
(3)
t- s sig S t- TYPE kind" t- $1 sig S, $1 t- L kind
(4)
S t- K A L L ( S 1 ) L kind t- $1 sig S, $1 t- L kind
(5)
S t- KSOME(S1)L kind"
Rule 3 says that TYPE is a kind under any signature. Rule 4 says that if $1 is a valid signature and for a given signature S, $1, L is a kind; then under the signature S, KALL(S1)L is a valid kind. Rule 5 is similar to rule 4 but for KSOME.
Arguments
(6) (7)
t- S sig S t- empty = empty" S t- S1 = D1 S t- a: A xc(DV(S) U DV(S1)) St- $1, x : A = D1, a
These two rules say that an argument satisfies (or matches) a signature if the components of the argument are in the proper order and of proper type according to the signature.
Types and operators (8)
t- S sig XcDV(S)
if X : K in S.
St-X:K
(9)
t- S1 sig S, S1 t- A: TYPE S t- ALL(S1)A: TYPE t- S1 sig S, S1 t- A: TYPE
(10)
S t- SOME(S1)A: TYPE t - S l s i g S, S l t - A : L
(11)
S t- FUN(S1)A: K A L L ( S 1 ) L " S t- A: KALL(S1)L S t- D --- $1
(12)
(13)
S t- A ( D ) : L [ D / S v ] St- D--- $1 S, S l t - A : L S t- (O, A): KSOME(S1)L" S t- A: KSOME(S1)L S, Z: K S O M E ( S 1 ) L t- K kind
(14)
S, $1,
Y:Lt-
B:K[(S1, Y:L)/Z]
S t- BIND S, Y : L = A IN B : K [ A / Z ] (15)
S t- b: bool S t- A: TYPE S t- B: TYPE S t- IF b T H E N A ELSE B
Rule 11 deals with valid (well typed) functions and their kind, where the values of the functions are types (type term abstractions). Rule 12 concerns valid application and its kind; it says that if A has kind
W. Li / Type-theoretic approach for program development
59
KAL(S1)L, and the argument D (actual parameters) satisfies (matches) S1, then A(D) is a valid application and has kind L[D/Sv]. Note that the type of result of an application may depend on the values of parameters. Rule 13 deals with tuples, where the type term A may depend on the variables defined in S. Rule 14 concerns the splitting of tuples into their components; it says that if A is a valid type of kind KSOME(S1)L, K is a valid kind which may depend on type Z of kind KSOME(S1)L, and B is a valid type of kind K, then term BIND S, Y : L = C IN B is a valid type of kind K.
Objects (16)
~- S sig x(DV(S)
if x: A in S.
S~-x:A F-S1 sig S, S1 ~ - A : L (17)
(18)
S ~- fun(S1)a: ALL(S1)A" S ~ a: ALL(S1)A S ~- D : $1
S ~ a(D): a[D/Sv]
S~D-S1 S, S1 ~ a : A (19) S ~-
(20)
S, Sl, y: A ~ d: B[(S1, Y: L)/z] S ~- bind S, y: A = a in d : B [ a / z ]
(21) (22)
S ~ - A : TYPE S, x : A ~- a : A S ~- recfun(x : A)a: A S~-b:boolS~-a:A S~-e:B S F- if b then a else e: IF b T H E N A ELSE B"
The rules for objects are similar to the rules for types. Rule 21 says that if A is a type and for given context S, x : A a has type A then the recursive function recfun (x : A) a has type A. Rule 22 says that the type of "if b then a else e" is " I F b T H E N A ELSE B" provided b, a and e have proper types under a given context S.
6. A d)namic semantics of ALT Dynamic semantics play an important role in the structural operational approach. It defines computations (or performances) of programs in terms of transitions (see [14] and [10]). The dynamic semantics of ALT is defined by one step transitions. In fact, it is a generalized Beta-Eta reduction for typed lambda calculus (see [9]). Since valid terms are fully dealt in the static semantics we define dynamic semantics only for valid terms. It is clear that different syntactical entities need different transitions to specify their computation, so we use S~-K~K' k tO mean that in the environment S, a kind term K can be transformed (or reduced) to a term K'. We use S ~- T --, T ' t
to mean that in the environment S a type term T may be transformed (or reduced) to a term T'. We use SF-a~
a' 0
W. Li / Type-theoretic approach for program development
60
to mean that in the environment S, an object term t may be transformed (or reduced) to a'; and use S~- S1 --, S' s
to mean that in the environment S, an signature $1 may be transformed (or reduced) to S'; and use S~-D~D' d
to mean that in the environment S, an argument term D may be transformed (or reduced) to D'. We will omit k, t, o, s and d under the arrows when there is no confusion in the context. The transition for kinds is defined by the following axioms and rules:
Kinds SOF- S - , S' (1) SO ~- K A L L ( S ) L --, K A L L ( S ' ) L "
(2) (3)
(4)
S0~- L - , L' SO ~ K A L L ( S ) L ~ K A L L ( S ) L ' " S0~- S - , S' SO ~- KSOME(S)L --, KSOME(S)L'" S0 F- L - * L' SO F- KSOME(S)L --, KSOME(S)L'"
The transitions for types and type operations are defined by the following axioms and rules:
Types and operators
(5) (6)
S0 t- S--+ S' SO ~- ALL(S)A --+ A L L ( S ' ) A " S0 ~- A - + A' SO ~ ALL(S)A --+ ALL(S)A " S0~- S-+ S'
(7) SO ~- SOME(S)A ~ S O M E ( S ' ) A " SO ~- A --* A' (8) SO ~ SOME(S)A --, SOME(S)A'" (9) SO ~- F U N ( S ) A ( D ) --, A [ D / S v ] (10) SO I- F U N ( S ) ( A ( S v ) ) ~ g . SOF- S ~ S' (11) SO t- F U N ( S ) A -+ F U N ( S ' ) A " (12) (13)
S0~- A ~ A' SO ~- F U N ( S ) A ---+FUN(S)A' " S0 ~- A-", A' SO ~- A ( D ) --* A ' ( D ) "
S0 ~- D--+ D ' (14) SO t- A(D) --+ A ( D ' ) " S0 t- D--+ D ' (15) SO I- (D, A) --, ( D ' , A ) "
W. Li / Type-theoretic approach for program development
(16)
61
SO ~ A ~ A' S0 ~- ( D , A) ~ ( D , A ' ) "
(17) SO ~ B I N D S = D I N B -+ B [ D / S v ] . (18)
S0~A-,A' S0~BINDS=AINB~BINDS=A'INB"
(19) SO ~- IF tt T H E N A ELSE B ~ A.
(20) (21)
SO ~- If ff T H E N A ELSE B ~ B. S0~- b ~ b ' SO ~- IF b T H E N A ELSE B ~ IF b' T H E N A ELSE B "
Rule 9 and 10 are generalized forms of Beta and Eta reduction respectively. Rule 17 says that when A (the right hand side of the equations) is an argument the term B I N D is reduced to a new term obtained from B by substituting D for Sv. The other rules are saying that transitions of a compound type term are determined by transitions of their components. The transition for objects is defined below:
Objects (22) SO ~- fun(S)a(D) ~ b I D / S v ] . (23) SO ~ fun(S)(a(Sv)) ~ a. (24)
(25)
(26)
S0~- S ~ S' SO ~- fun(S)a ~ f u n ( S ' ) a " S0~- a ~ a ' SO ~- fun(S)a -~ f u n ( S ) a ' " S0~- a ~ a ' SO ~- a ( D ) ~ a ' ( D ) "
S0~- D ~ D ' (27) SO ~- a ( D ) ~ a ( D ' ) " S0~- D ~ D ' (28) SO W ~D, a) ~ ~D', a ) " S0~a~a' (29) SO ~- ( D , a) ~ ( D , a ' ) " (30) SO w bind S = D in b ~ b [ D / S v ] . (31)
(32)
SO ~- a ~ a' SO ~- bind S = a in b ~ bind S = a ' in b" SO ~- a[recfun(x : A ) a / x ] -~ a ' SO ~- recfun(x : A)a ~ a '
(33) SO ~- if tt then a else e ~ a. (34) SO ~- if ff then a else e ~ e. (35)
SO ~- b ~ b' SO ~ if b then a else e ~ if b' then a else e"
Similar to the rules for types, rule 22 and 23 deal with Beta and Eta reduction respectively. Rule 30 concerns the transition of term bind when a is an argument D. The other rules are saying that transitions
W. Li / Type-theoretic approach for program development
62
of a compound term are determined by transitions of their components. The transitions for signature are defined below: Signature S0 ~-A ~ A'
(36)
SO ~- S, x : A ~ S, x:A'" SO ~- S--, S' (37) S0~- S, x:A---, S, x : A "
The transitions for arguments are defined as follows: Arguments SOF- a ~ a' ,. S0 F- D, a ~ D , a SOF- D ~ D' (39) SO~- D, a ~ D', a" (38)
The transitions for signatures and arguments say that the evaluations of them can be done by evaluating their components separately.
7. Interactions betxveen static attd d3namic ~emanlics The interaction between static semantics and dynamic semantics is defined by the following rules:
(1)
SF-A:K
(2)
S~a:A
S~-K'kind S~-A:K' S~-A'TYPE S~- a : A '
S~-K--,K' S~-a--,a'
8. Conclusions We have given the basic paradigm of program development using type theories, after analyzing some typical examples concerning type theories. We have then designed a language ALT. It is a language description of a generalized high-order typed lambda calculus with/-/, 2: types a n d / I , 2: kinds. Through four major examples we have shown how this language plays a key role in this approach. We have presented a formal description of ALT using a structural operational approach which may help readers understand the meanings of ALT constructs precisely without involving too many details about concrete syntax. Much more work remains to be done, and we believe that ALT can be used as a powerful tool to implement many higher order concepts from software engineering and artificial intelligence.
Acknowledgement~ I thank Steve Brookes for the encouragement, and thank David Rydeheard and Tang Zhisong for helpful discussions and reading an early draft of this paper.
References [1] A. Avron, F.A. Honselland I.A. Mason, Using typed lambda calculus to implementformal systemson a machine,Technical report of LFCS,ECS-LFCS-87-31,Universityof Edinburgh(July 1987).
W. Li / Type-theoretic approach for program development
63
[2] M. Broy, Algebraic methods for program construction: The project CIP, Program Transformation and Programming Environments (NATO ASI Series, 1984). [3] L. Cardelli, Polymorphic \-calculus with Type: Type, Technical report No. 10, System Research Center (May 1986). [4] L. Cardelli, Structural subtyping and the notion of power type, Proc. POPL (1988). [5] L. Cardelli, A quest preview, A draft of technical report, System Research Center (January, 1988). [6] T. Conquand and G. Huet, A high-order proof system for mechanizing mathematics, EUROCAL "85 (Springer-Verlag, 1985). [7] R.L. Constable, Implementing Mathematics with the Nuprl Development System (Prentice-Hall, 1986). [8] R. Harper, F. Honsell and G. Plotkin, A framework of defining logic, Proc. Symposium on Logic in Computer Science (IEEE Computer Society, June 1987). [9] J. Hidley and J. Seldin, Introduction to Combmators and Lambda Calculus (Cambridge University Press, 1986). [10] W. Li, An operational approach to semantics and translation theory for concurrent programming languages, Ph.D. thesis, University of Edinburgh (January 1983). [11] P. Martin-LSf, Constructive mathematics and computer science, in: Sixth International Congress for Logic, Methodology and Philosophy of Science (North-Holland, Amsterdam, 1982). [12] P. Martin-Ltif, Intuitionistic type theory, Studies in Proof Theory Lecture Notes, BIBLIOPOLIS (Napoli, 1984). [13] L. Paulson, Natural deduction proofs as high-order resolution. J. Logic Programming 3 (1986). [14] G. Plotkin, A structural approach to operational semantics, a lecture note, Dept of computer science, Aarhus University (September 1981). [15] L.A. Zadeh, Fuzzy logic and approximate reasoning, Syntheses 30 (1975).