You are on page 1of 14

Avoiding dynamic type checking in a polymorphic logic programming language

Pascal Brisset

IRISA Campus Universitaire de Beaulieu, F-35042 Rennes Cedex, France


brisset@irisa.fr

Abstract
For obvious e ciency reasons, it is good to avoid dynamic type-checking in a programming language. The Prolog type system proposed by Mycroft and O'keefe has some good properties which avoid such a runtime overhead. One of this property called type preserving or transparency is a restriction of the polymorphism. This restriction is not compatible with some programming techniques, for example with higher-order predicates. Considering a type system without the type preserving property, Hanus has identi ed some cases where dynamic type-checking can be strongly limited. We show in this paper that in Hanus' solution, too many types are still dynamically represented and checked. We propose an implementation where, without the type preserving restriction, dynamic type checking is done exactly for types which are not preserved. This approach is used in an implementation of the higher-order language Prolog.

Keywords Types, polymorphism, higher-order uni cation, Prolog, dynamic type-checking, implementation.

1 Introduction
It is no longer necessary to show the usefulness of types in a logic programming language. As mentioned by Pfenning 18], one of the main motivation is that \types help to detect programming errors at compile-time". Furthermore types can also help the compiler to do some optimizations. Type systems can be roughly divided into two categories 20]: In a prescriptive type system, terms are intrinsically typed; In a descriptive type system, the terms are decorated with types. In the former category, types are in the de nition of the terms thus the semantics and the interpretation of the language must take these types into account. In the latter category, terms are only mapped to types with a \have type" function. This mapping gives a structure to the model of the program but does not change this model. 1

One of our motivation is to implement a type system for Prolog 16]. Prolog uses a typed logic, i.e. needs types. Therefore we are interested in a prescriptive type system. Even if the motivation is the language Prolog, the ideas we expose in this paper can be applied to the implementation of a polymorphic type system for standard Prolog. Even with a prescriptive type system, types may not be explicit in the program; the types may be inferred. In this case, the programmer think about typed terms, but write programs without types. Then a type-checker adds types to the terms. In our work, we have chosen to have type declarations because these declarations help the programmer to specify his problem correctly. The more the user gives information about his program, the more precise the compiler does the checking. Numerous type systems have been proposed for Prolog 19]. One of the main features addressed in these type systems is polymorphism and one of the main constraints is that polymorphism does not introduce dynamic typechecking. Therefore, polymorphism is restricted. The restriction we discuss here is called type preserving by Hanus 5, 6] or transparency property by Hill and Topor 8]. Hanus showed that this restriction is not compatible with higher-order programming. Because we have the Prologlanguage in mind, for which higher-order programming is a standard technique, we cannot keep this restriction. Hanus showed that some dynamic type-checking in a type system without the restriction can be sometimes avoided. We show in this paper that Hanus' solution can be improved and that most of the dynamic type-checking can be simply omited without any complex static analysis. We also address the problem of dynamic type representation in Prolog in which types are necessary to compute the uni cation. The paper is structured as follows. In section 2, a type system for Prolog is proposed. It is then extended to the Prolog case. In section 3, we show which types are su cient at runtime. In section 4, some modi cations of the standard data-structures and uni cation algorithm are proposed to take the types into account. We conclude with a discussion about related works.

2 A Type System and its Properties


In this section we recall a classic type systems for Prolog and Prolog. We discuss and justify the adoption of some restrictions, i.e. type preserving and de nitional genericity.

Types, Terms and Formulas A type (denoted , , ...) is an expression

2.1 Typed Prolog

built from type constructors and type variables. Each type constructor has an arity (e.g., int has arity 0, list has arity 1). There is a type of arity 0 called o, the type for propositions. 2

We write 1 2 if the type 1 is an instance of 2: 1 = s( 2) where s is a substitution on type variables. We write 1 = 2 if 1 and 2 are equals to a renaming of the type variables. Terms in our typed Prolog are rst-order terms. Every constructor f of terms with arity n is declared with a type scheme:
f : (T1, ..., Tn) -> T

where T1, ..., Tn, T are arbitrary types. T is then called the result type. We voluntarily do not distinguish the type declaration of a function symbol from the type declaration of a predicate. The result type of a predicate is o. We note (f ) the type scheme (from the type declaration) of the function f . A program is a set of clauses L L1 ^ ::: ^ L (n possibly 0) where L,L1,...,L are literals. A literal is a term of type o, i.e p(t1 ; :::; t ) with p a predicate symbol. In the concrete syntax, logic variables and type variables identi ers start with an uppercase letter, function and predicate symbols start with a lowercase letter.
n n q

(see also Typed Prolog 11]) and give motivations for such a system.
variable : ?; X : ` X : atom : ? ` a :
n

The type system We brie y recall here Mycroft-O'Keefe type system 15]
(a) (f )

1 : 1 : : : ? ` tn : compound term : ? ` t ? ` f (t1 ; : : :; tn) :

( 1 ; : : :; n) !

1 : : : ? ` t k : k ? ` B1 : o : : : ? ` B n : o clause : ? ` t1 :? ` p(t1; : : :; tk ) B1 ^ : : : ^ Bn : o

(p) = ( 1 ; : : :; n ) ! o

The two basic ideas behind this type system are that every clause should be well-typed in an ML-like fashion. First, Types of di erent occurrences of a constant are independent instances of its type scheme ( condition in the atom and compound term rules), and second, the typing of predicate should obey the de nitional genericity principle (also called head condition in 8]) Types of body occurrences of a predicate constant are independent instances of its type scheme, whereas types of head occurrences are only renaming of the type scheme (= condition in the clause rule). For the rst idea, checking and inferring types are both decidable, as in ML 14], but for the second idea, only type checking is decidable. With the de nitional genericity principle, type inference leads to a non-uniform 3

semi-uni cation problem which has been shown to be undecidable by Kfoury, Tiuryn and Urzyczyn 10]. One reason for sticking to de nitional genericity (or head condition) is that it is the most natural when predicates are seen as de nitions and type schemes as abstractions of the de nitions. A sound and easy modular analysis of programs also requires de nitional genericity. The other reason is that de nitional genericity corresponds to implementation genericity: we do not want to take into account the type of the arguments of the goal to select the right clause. From a software engineering point of view it means that if the user speci es a generic type for a predicate, he also gives a generic de nition of this predicate. For example, assume predicate constant append is declared as
append : (list(A), list(A), list(A)) -> o.

and that clause


append 1] 2, 3] 1, 2, 3].

is added to the standard de nition of predicate append. It violates the de nitional genericity principle because the type of constant append in the new clause,
(list(int), list(int), list(int)) -> o

is a strict instance of the type scheme. An expected outcome of a type theory for a programming language is a semantic soundness result that states that \well-typed programs cannot go wrong" where \going wrong" means \trying to solve ill-typed uni cation problems". The interest of such a result is to give formal grounds for not representing types at run-time. We will see in the next section that for pragmatic programming reasons, it is not possible to have this property in a polymorphic type system for Prolog.

2.1.1 Type Preserving and Higher Order Programming


The type declaration languages of ML or Typed Prolog share a common restriction that ensures the type preserving property 7]: Every type variable in a type scheme should appear in the result type. For example in ML, type variables of a type declaration must occur in the left side: the declarations for constants cons and nil can be written in ML as
datatype 'a list = nil | cons of 'a * 'a list

This ensures that well-typed programs cannot go wrong 15]. This restriction makes it always possible to derive the type of subterms from the type of a term. Hanus 6] showed that this type preserving restriction, coupled with definitional genericity, is not compatible with higher-order programming. Consider the map predicate:
map : (pred(T1, T2), list(T1), list(T2)) -> o. map(_P, ], ]). map(P, A | L], PA, PL]) :- apply(P, A, PA), map(P, L, PL).

The map predicate applies a binary predicate to every element of two lists. Because we want to use this map predicate on di erent types of list (we recall that a list has the type list(T) if all its elements have the type T), the apply predicate cannot obey to the principle of genericity:
apply(inc, N, N1) :- N1 is N + 1. apply(car, L, CarL) :- L = CarL | _].

In the rst clause, the second argument of apply has type int and in the second clause, it has type list(T), two types which cannot be uni ed. It is possible to solve the problem using a function symbol f : T -> i (where i is any type constructor of arity 0):
map(_P, ], ]). map(P, A | L], PA, PL]) :- apply(P, f(A), f(PA)), map(P, L, PL). apply(inc, f(N), f(N1)) :- N1 is N + 1. apply(car, f(L), f(CarL)) :- L = CarL | _].

Here the types of the second and third arguments of apply are i. The typing problem has been solved using the f constant which forgets the type of its argument. This solution does not obey to the type preserving principle. Note, that even using a higher-order syntax (e.g. Prolog), the problem appears:
map(_P, ], ]). map(P, A | L], PA, PL]) :- P(A, PA), map(P, L, PL). inc(N, N1) :- N1 is N + 1. car(L, CarL) :- L = CarL | _].

With such a program, a call looks like map(inc, 1,2], 2,3]). Because the predicate car can appear as a term and because its type is (list(A), A) -> o, the type preserving property is still not veri ed. In fact, this particular program does no go wrong (i.e. all uni cations are well-typed) but it cannot be proved in the standard way. Because we want to keep the de nitional genericity principle and because we have the typing of an higher-order logic programming language (i.e. Prolog) in mind, it is impossible to have the type preserving property. 5

It is straight forward to show now that, without the type preserving property, a program statically well typed-checked is not dynamically well typed. For example, the following program goes wrong if no dynamic checking is done.
eq : (A, A) -> o. forget : A -> i. query :- eq(forget(1), forget("1")).

2.1.2 Well-typed programs may \go wrong"

It is perfectly well-typed, but it goes wrong because the execution eventually produces uni cation problem < 1, "1" >, which is ill-typed (1 has type int while "1" has type string). In a prescriptive type system, the solutions of such an ill-typed uni cation problem are not de ned.
2.2 Prolog We brie y (and informally) present the extension of Prolog to higher-order hereditary Harrop formulas. The description is given using the concrete syntax of Prolog. This syntax slightly di ers from the syntax of Prolog in order to encode better higher-order features.

from a collection of type constants, a collection of type variables and one dedicated binary type constant, '->' (right associative). Intuitively, A -> B is the type of functions from terms of type A to terms of type B. Note that we adopt a di erent syntax for types of Prolog and types of Prolog. For example, the type of cons which were noted (A, list(A)) -> list(A) is noted in Prolog A -> (list A) -> (list A). Simply typed -terms are built from a collection of constants, a collection of variables, a collection of logic variables and two construction rules, abstraction (x\ E ) and application ((E F )). Each constant must be declared with the 'type' directive, specifying the type of the constant: type cons A -> (list A) -> (list A). declares cons as a constant of type A -> (list A) -> (list A). Three equivalence relations are de ned on the set of terms. -equivalence de nes consistent renaming of variables. -equivalence de nes the consistent reduction of an application (x\ E F ) (called a -redex) into E where each free occurrence of x is substituted in E by F . -equivalence formalises extensionality of -de ned functions. The uni cation of simply typed terms taking into account the three equivalence relations is a non-decidable and in nitary problem: there may be in nitely many most general solutions 9]. So, the algorithm of uni cation is not deterministic. A Prolog program is a set of declarations and an ordered set of clauses. Like in Prolog, the constructor of non-empty body clauses is ':-', the conjunction constructor is ','. 6

Types, Terms and Formulas Simple types 4] are rst-order terms built

A Type System We give here a type system for Prolog. It di ers from the type system of Prolog by the syntax and the new rule for the abstraction.
variable : ?; X : ` X : atom : ? ` a : (a) 2 ? ` t2 : 1 application : ? ` t1 : ?1`! t1 t2 : 2 1 : : : ? ` t k : k ? ` B1 : o : : : ? ` B n : o clause : ? ` t1 : ? (p) = 1 ! : : : k ! o ` p t1 : : :tk B1 ^ : : : ^ Bn : o ;x : 1 ` t : 2 abstraction : ??` x:t : 1 ! 2 Note that the variable rule works for both logic variables and variables

from abstractions.

2.3 Higher-Order Uni cation needs types We recall in this section why in Prolog, types are necessary for uni cation. See 9] for a complete description of the higher-order uni cation algorithm.

(F T1) with any term where T1 is a term and F is a logic variable. The projection rule of the higher-order uni cation algorithm starts the uni cation by unifying F to x:x if the result type F is equal to the type of T1. A way to check this prerequisite is to check that the argument type of F is equal to the result type of F . This needs to know only the type of F . For example if the type of F is 1 ! 2, the projection rule is applied only if 1 and 2 are uni able. the exible term (F 1) with (+ T1 T2). The imitation rule of the uni cation algorithm leads to the substitution F = x:(+(H1 x)(H2 x)) where H1 and H2 are new logical variables. These variables must be typed properly. They have types int ! 1 and int ! 2. The types can be inferred from the type of the constant +. It is the type of the corresponding argument T . It remains to be able to infer the type of the constant, i.e. the type of the occurrence of the constant, not its type scheme. For example, we may have (+) = ! ! and the result type of F equal to int. We then can infer the types of H1 and H2 which is int ! int.
i i

Logic variables must carry their types Suppose we have to unify

Types of constants must be computable Suppose we have to unify

3 Necessary Types
Observations of the previous sections mean that types must be kept at runtime so that type uni ability can be checked before term uni ability. In fact, only parts of types have to be kept. 7

3.1 Which types are su cient: forgotten types We showed in section 2.1.2 that, without the type preserving property, a program may \go wrong". So, a simple idea is to represent the types which are not preserved and to do a check on these not-preserved types at runtime. It is only necessary to represent the types which are instances of the type variables that do not appear in the result type of a declaration (for example T2 in the type scheme pair(T1, T2) -> T1). We call these types the forgotten types. In order to explicit these forgotten types, we will use a wild extension of our type de nition with more polymorphic types: second-order types 18].

Notation and de nition: Let = ( 1; :::; ) ! be a type scheme. Let


F

= v1 ; :::; v be the variables of which do not appear in . is noted with the following explicit quanti cations v1 ::: v ( 1; :::; ) ! . Let be a type instance of : = s( ). The images of F by the substitution s are called the forgotten types of .
p p n
0 0 0

We use the prenex symbol 'PI' for the product type quanti er in the concrete syntax. For example, the type scheme pair(T1, T2) -> T1 is written 'PI' T2\ (pair(T1,T2) -> T1) and the symbol forget may be declared forget : 'PI' A\(A -> i) Following this notation, our proposition is:

To represent only the forgotten types at runtime.


Then terms will be represented as if the function symbols were declared with the explicit quanti cation on the forgotten variables. So, term forget(1) is coded as forget(int, 1) and term forget("1") is coded as forget(string, "1"). We consider a generic uni cation algorithm for types and terms. We suppose that this algorithm works from left to right on the arguments (types and subterms) of a term. It means that the forgotten types of a term are uni ed before its subterms.
types does not go wrong. This proposition ensures that compile-time type checking plus dynamictype cheking on forgotten types are enough to get a well-typed execution. Proof: The proof is done by induction on terms.

Proposition: A uni cation algorithm which works on terms with forgotten

Initial case: A uni cation problem always starts with two literals which have the type o. Suppose we have to unify the two terms f ( 1 ; : : :; ; t1; : : :; t ) and f ( 1; : : :; ; t1 ; : : :; t ) where the are the forgotten types. The induction hypothesis says that the two terms have the same type . We
p n
0 0

Note that, unlike other presentations, there is no special syntax for declaring predicate constants. They are only distinguishable by their result type, o. So, every predicate constant forgets every type variable in its type scheme because its result type (o) contains no type variable. It can be shown that if the predicate obeys the de nitional genericity principle, uni cation of these forgotten types always succeeds; type uni cation is only required for conveying types along the computation. In fact, if the type preserving restriction were imposed on functional constants only, well-typed programs could not go wrong 15, 7, 11] (except of course with higher-order programming). To sum up Forgotten types of both function and predicate constants need to be represented at run-time Only forgotten types of function constant need to be uni ed at runtime. Forgotten types of predicate constants are just passed. So, type preserving constants (such as ]:list(A) and cons:(A,list(A))->list(A)) are implemented in the standard way, i.e. with no type information. Hanus has shown that it is not necessary to represent (and check at runtime) the type of the arguments of a type preserving function. Our result is more precise: it is only necessary to represent the types which are not preserved by a constant. On the Hanus' map example 6], it means that, instead of the proposed
map(P:pred(A, B), E1|L1]:list(A), E2|L2]:list(B))

have to prove that t has the same type than t for every i after each type has been uni ed with . The type of the two f occurrences = ( 1; : : :; ) ! and = ( 1; : : :; ) ! are instances of the same type scheme (f ): = s( (f )) and = s ( (f )) where (f ) = v1::: v ( 1 ; :::; ) ! . For every i we have = s(v ), = s (v ) and = . By de nition, all the other variables of (f ) (di erent from the v 's) occur in (the result type) and we have s( ) = = s ( ). So s = s and then s( ) = = s ( ) = , i.e. the type of t is equal to the type of t for every i.
i
0

following the type declaration (A and B are forgotten types in the type of map):
map : 'PI' A\ 'PI' B\ ((pred(A, B), list(A), list(B)) -> o)

only the goal


map(A, B, P, E1|L1], E2|L2])

is needed for correctly typed uni cation. 9

3.2 The Prolog case Because of needs of higher-order uni cation, more types need to be represented in the Prolog case. Firstly, type of the logic variables must be fully represented in order to be able to apply the projection rules of the uni cation algorithm Secondly we saw that application of the imitation rule need to be able to infer the type of any constant. We observe that the type scheme of a constant, plus the forgotten types attached to it, plus the result type give enough information for reconstructing the type of the constant. During uni cation, the result type can be found in the type of the exible head (see 2.3). Note that the result type cannot be reconstructed only from the forgotten types because it may contain instances of non-forgotten type variables (type variables occurring in the result type of the type scheme). To sum up, typed higher-order uni cation needs only (plus the forgotten types as in the rst-order case):

The type of the logic variables (dynamically represented); The type scheme of the function symbols (dynamically reconstructed). More details about the handling of types in Prolog are given in the next section.

4 Implementation
We give in this section the modi cations which are necessary to do on a standard implementation of Prolog 1] to handle a typed Prolog without the type preserving property.
4.1 Prolog We have shown that, in order to have a correct interpretation of a typed Prolog program. i.e. with well-typed uni cation problems, it is only necessary to represent the forgotten types. This leads to a modi cation of the data-structures and the uni cation algorithm. The number p of forgotten types of every function f=n (f has arity n) is computed at compile-time, from the type declaration of the constant f . A structure of functor f is then represented by an array of size 1 + n + p. The forgotten types are represented as usual subterms of the structure. So, for each construction of a structure with forgotten types there will be instructions to create these types. Because types are essentially rst-order terms, it is not necessary to distinguish the types from the terms. So, we do not need to modify the standard abstract machine. The compiling process is modi ed to take into account the types but the modi cation may be transparent to the uni cation.

10

As we have shown, it is only necessary that the forgotten type are uni ed before the other subterms of a structure. We note that because of the de nitional genericity of the type system, the uni cation of the forgotten types in the head of a clause is reduced to a parameter passing, i.e. a get_variable WAM instruction. Example: (from 17]) We give the type declaration with the explicit quanti cation on forgotten variables to clarify the compilation process.
fst : 'PI' T2\ pair(T1, T2) -> T1. snd : 'PI' T1\ pair(T1, T2) -> T2. rel_pair : 'PI' T1\ 'PI' T2\ (pair(T1, T2), pair(T1, T2)) -> o. rel : 'PI' T\ (T, T) -> o. rel_pair(X, Y) :- rel(fst(X), fst(Y)), rel(snd(X), snd(Y)).

After compile-time type checking, we get the following program with the forgotten types as new arguments corresponding exactly to the quanti cations:
rel_pair(T1, T2, X, Y) :rel(T1, fst(T2, X), fst(T2, Y)), rel(T2, snd(T1, X), fst(T1, Y)).

This program is then compiled in the usual way (provided that types and terms are not distinguished). We remark that it is not necessary to extend the WAM to execute this typed program. Because of this mixing of types and terms, we get for free all the usual optimisations (as register allocation) for the handling of the types.
4.2 Prolog The implementation of the types in Prolog is more complex than in Prolog for two reasons (see 2.3): Every logic variable must carry its type.

It must be possible to reconstruct the type of any constant occurrence. First, the type of the logic variables must be represented. This type may be attached to the variable using the now well-known attributed variable 12] also called metaterm 13]. Secondly, the uni cation algorithm must be able to reconstruct the type of any constant. We propose here a compiled solution. A type reconstruction function is generated at compile-time from every type scheme declaration. Such a function takes the result type as a parameter. Let U be a function returning the most general uni er (a substitution) of two types. To every constant with a type scheme = v1::: v : , whose result type is (by de nition, it cannot depend on forgotten types), we associate the type reconstruction function v1 :::v :(U ( ; )( )).
p
0

11

The type reconstruction function must be applied to the actual forgotten types of some occurrence of the constant and to the result type of the matching logic variable . Type checking makes it sure that U ( ; ) de nes a substitution. For example, let the following declaration
f : A -> B -> (t B).

Type variable A is forgotten, hence the declaration is read as


f : 'PI' A\(A -> B -> (t B)).

The type reconstruction function is a :U ((t B); )(a -> B -> (t B)). The two parameters of the function are a the forgotten type and the result type. The function uni es with (t B) (where B is a new type variable) and returns the type a -> B -> (t B). With these declarations, uni cation problem <(F 1),(f 1 1])> is actually represented as
< (F:(int -> (t (list int))) 1) , (f int 1 1]) > .

The imitation rule yields the substitution


x\(f int (H1 x) (H2 x)) / F] .

which introduces new logic variables H1 and H2. For typing them, the type reconstruction function is called with types int and (t (list int)) as parameters. It uni es (t (list int)) and (t B), producing the substitution (list int) / B], and applies the substitution to the type scheme in which the forgotten type variable is replaced by int. So, the actual type of this occurrence of constant f is reconstructed: int -> (list int) -> (t (list int)). Then, logic variables H1 and H2 are given types int -> int and int -> (list int).

5 Related work
The comparison of our solution with Hanus' one has been done in section 3.1. Hanus has proposed an optimisation for constants which verify the preserving property only while our improvement is done on every constant, considering precisely its type. However, the optimisations based on mode analysis proposed by Hanus can be added to our solution in order to remove more type representation and uni cation. Nadathur and Wilson 17] have described an implementation of a polymorphic typing in Prolog. They propose to represent the type of the symbols and the logic variables. We have shown in this paper that, in the rst-order 12

(Prolog) case, the type of the logic variables is not useful to have a well-typed execution. Note that the proposed type reconstruction function (see 4.2) is not equivalent to the skeleton idea proposed by Nadathur. The skeleton is a function able to reconstruct the type of a constant from the instances of all the type variables in the type scheme. In our scheme the non-forgotten types are not directly available: the instance of the non-forgotten variables are derived from the uni cation of the result type.

6 Conclusion
We have recalled that the type preserving property of type systems is not compatible with higher-order programming. We have described an economical representation of types and dynamic type-checking. We have proved that the representation of the types which are not preserved is su cient to have a well-typed execution. Lastly, we have given some hints on the represention of types required by the higher-order uni cation in Prolog. The ideas presented in this paper have been validated by the implementation of the typing in the Prolog compiler PM 3, 2].

Acknowledgements We wish to thank M. Ducasse for her helpful remarks and O. Ridoux for his proof-reading.

References
1] H. A t-Kaci. Warren's Abstract Machine: A Tutorial Reconstruction. MIT Press, 1991. 2] P. Brisset and O. Ridoux. The architecture of an implementation of Prolog: Prolog/Mali. In Workshop on Prolog, Philadelphia, PA, USA, 1992. ftp: //ftp.irisa.fr/local/lande. 3] P. Brisset and O. Ridoux. The compilation of Prolog and its execution with MALI. Technical Report 687, IRISA, 1992. ftp: //ftp.irisa.fr/local/lande. 4] A. Church. A formulation of the simple theory of types. J. Symbolic Logic, 5(1):56{68, 1940. 5] M. Hanus. Horn clause programs with polymorphic types: Semantics and resolution. In TAPSOFT'89, LNCS 352, pages 225{240. SpringerVerlag, 1989. 6] M. Hanus. Polymorphic higher-order programming in Prolog. In G. Levi and M. Martelli, editors, 6th Int. Conf. Logic Programming, pages 382{ 397. MIT Press, 1989. 13

7] M. Hanus. Horn clause programs with polymorphic types: Semantics and resolution. Theoretical Computer Science, 89:63{106, 1991. 8] P.M. Hill and R.W. Topor. A semantics for typed logic programs. In F. Pfenning, editor, Types in Logic Programming, pages 1{62. MIT Press, 1992. 9] G. Huet. A uni cation algorithm for typed -calculus. Theoretical Computer Science, 1:27{57, 1975. 10] A.J. Kfoury, J. Tiuryn, and P. Urzyczyn. The undecidability of the semiuni cation problem. Technical Report BUCS 89-010, Boston University, 1989. 11] T.K. Lakshman and U.S. Reddy. Typed Prolog: A semantic reconstruction of the Mycroft-O'Keefe type system. In Int. Logic Programming Symp., pages 202{217, 1991. 12] S. Le Huitouze. A new data structure for implementing extensions to Prolog. In P. Deransart and J. Maluszynski, editors, 2nd Int. Work. Programming Languages Implementation and Logic Programming, LNCS 456, pages 136{150. Springer-Verlag, 1990. 13] M. Meier and J. Schimpf. An architecture for Prolog extentions. In E. Lemma and P. Mello, editors, Third Int. Workshop on Extensions of Logic Programming, LNAI 660, pages 319{338. Springer-Verlag, 1992. 14] R. Milner. A theory of type polymorphism in programming. J. Computer and System Sciences, 17:348{375, 1978. 15] A. Mycroft and R.A. O'Keefe. A polymorphic type system for Prolog. Arti cial Intelligence, 23:295{307, 1984. 16] G. Nadathur and D.A. Miller. An overview of Prolog. In K. Bowen and R. Kowalski, editors, Symp. Logic Programming, pages 810{827, Seattle, Washington, USA, 1988. 17] G. Nadathur, D.S. Wilson, and K. Kwon. Implementing polymorphic typing in a logic programmming language, 1992. Submitted. 18] F. Pfenning. Dependent types in logic programming. In F. Pfenning, editor, Types in Logic Programming, pages 285{311. MIT Press, 1992. 19] F. Pfenning, editor. Types in Logic Programming. MIT Press, 1992. 20] U.S. Reddy. Notions of polymorphism for predicate logic programs. In K.A. Bowen and R.A. Kowalski, editors, 5th Int. Conf. and Symp. on Logic Programming, pages 17{34. MIT Press, August 1988. 14

You might also like