A Prolog Based Animation
of Twelf Specifications
Abstract
Specifications in the Twelf system are based on a logic programming interpretation of the Edinburgh Logical Framework or LF. We consider an approach to animating such specifications using a Prolog implementation. This approach is based on a lossy translation of the dependently typed LF expressions into the simply typed lambda calculus (STLC) terms of Prolog and a subsequent encoding of lost dependency information in predicates that are defined by suitable clauses. To use this idea in an implementation of logic programming a la Twelf, it is also necessary to translate the results found for Prolog queries back into LF expressions. We describe such an inverse translation and show that it has the necessary properties to facilitate an emulation of Twelf behavior through our translation of LF specifications into Prolog programs. A characteristic of Twelf is that it permits queries to consist of types which have unspecified parts represented by metavariables for which values are to be found through computation. We show that this capability can be supported within our translation based approach to animating Twelf specifications.
1 Introduction
The Edinburgh Logical Framework or LF [4] is a dependently typed lambda calculus that has proven useful in specifying formal systems such as logics and programming languages (see, e.g., [5]). The key to its successful application in this setting is twofold. First, the abstraction operator that is part of the syntax of LF provides a means for succinctly encoding formal objects whose structures embody binding notions. Second, LF types can be indexed by terms and, as such, they can be used to represent relations between objects that are encoded by terms. More precisely, types can be viewed as formulas and type checking as a means for determining if a given term represents a proof of that formula. Proof search can be introduced into this context by interpreting a type as a request to determine if there is a term of that type. Further, parts of a type can be left unspecified, thinking of it then as a request to fill in these parts in such a way that the resulting type is inhabited. Interpreting types in this way amounts to giving LF a logic programming interpretation. The Twelf system [9, 10] is a realization of LF that is based on such an interpretation.
An alternative approach to specifying formal systems is to use a predicate logic. Objects treated by the formal systems can be represented by the terms of this logic and relations between them can be expressed through predicates over these terms. If the terms include a notion of abstraction, e.g., if they encompass simply typed lambda terms, then they provide a convenient means for representing binding notions. By restricting the formulas that are used to model relations suitably, it is possible to constrain proof search behavior so that the formulas can be given a rulebased interpretation. The logic of higherorder hereditary Harrop formulas () has been designed with these ideas in mind and many experiments have shown this logic to be a useful specification device (see, e.g., [7]). This logic has also been given a computational interpretation in the language Prolog [8], for which efficient implementations such as the Prolog/Mali [1] and the Teyjus [11] systems have been developed.
The two different approaches to specification that are described above have a relationship that has been explored formally. In early work, Felty and Miller showed that LF derivations could be encoded in derivations by describing a translation from the former to the latter [3]. This translation demonstrated the expressive power of , but did not show the correspondence in proof search behavior. To rectify this situation, Snow et. al. described a transformation of LF specifications into formulas that allowed the construction of derivations to be related [12]. This work also showed how to make the translation more efficient by utilizing information available from a static checking of LF types, and it refined the resulting specifications towards making their structure more closely resemble that of the LF specifications they originated from.
The primary motivation for the work of Snow et. al. was a desire to use Teyjus as a backend for an alternative implementation of logic programming in Twelf. However, it falls short of achieving this goal in two ways that we address in this paper. First, although it relates derivations from LF specifications to ones from their translations, it does not make explicit the process of extracting an LF “result” term from a successful derivation; such an extraction is necessary if Teyjus is to serve as a genuine, invisible backend. To close this gap, we describe an inverse translation and show that it has the necessary properties to allow Twelf behavior to be emulated through computations from Prolog programs. Second, Snow et. al. dealt only with closed types, i.e., they did not treat the idea of filling in missing parts of types in the course of looking for an inhabitant. To overcome this deficiency, we include metavariables in specifications and treat them in the backandforth translations as well as in derivations; the last aspect, that is also the most critical one in our analysis, requires us to build substitutions and unification explicitly into our formalization of derivations.
The remainder of this paper is structured as follows. Sections 2 and 3 respectively present LF and the logic together with their computational interpretations. Section 4 describes a translation from LF specifications into ones together with an inverse translation for extracting solution terms from derivations. We then propose an approach for developing a proof of correctness for this translation. Section 5 improves the basic translation and Section 6 uses it to illustrate our proposed approach to realizing logic programming in Twelf. Section 7 concludes the paper.
2 Logic programming in LF
Three categories of expressions constitute LF: kinds, type families or types which are classified by kinds, and objects which are classified by types. Below, denotes an object variable, an object metavariable, an object constant, and a type constant. Letting range over kinds, and over types, and and over objects, the syntax of these expressions is given as follows: Both and are binders which also assign types to the (object) variables they bind over expressions. Notice the dependency present in LF expressions: a bound object variable may appear in a type family or kind. In the remainder of this paper we use and ambiguously for types and objects and similarly for types and kinds. The shorthand is used for if is a type family or kind that is not dependent on the bound variable, i.e. if does not appear free in . Terms differing only in bound variable names are identified. We write to denote the capture avoiding substitution of for the free occurrences of respectively in .
LF kinds, types and objects are formed relative to a signature that identifies constants together with their kinds or types. In determining if an expression is wellformed, we additionally need to consider contexts, denoted by , that assign types to variables. The syntax for signatures and contexts is as follows:
In contrast to usual LF presentations, we have allowed expressions to contain object metavariables. We assume an infinite supply of such variables for each type and that an implicit metavariable context assigns types to these variables. These metavariables act as placeholders, representing the part of an expression one wishes to leave unspecified.
metavar
constobj  absobj 
varobj 
appobj 
Complementing the syntax rules, LF has typing rules that limit the set of acceptable or wellformed expressions. These rules define the following mutually recursive judgments with the associated declarative content: is a valid signature is a valid context relative to the (valid) signature is a valid kind in signature and context is a type of kind in a signature and context is an object of type in signature and context In our discussion of logic programming, we rely on a specific knowledge of the rules for only the last of these judgments which we present in Figure 1; an intuition for the other rules should follow from the ones presented and their explicit presentation can be found, e.g., in [4]. By these rules we can see that if a wellformed expression contains a meta variable of type , then replacing the occurrences of with a well formed object of type will produce an expression which is also wellformed.
The rules in Figure 1 make use of an equality notion for LF expressions that is based on conversion, i.e., the reflexive and transitive closure of a relation equating two expressions which differ only in that a subexpression of the form in one is replaced by in the other. We shall write for the normal form of an expression, i.e., for an expression that is equal to and that does not contain any subexpressions of the form . Such forms are not guaranteed to exist for all LF expressions. However, they do exist for wellformed LF expressions [4], a property that is ensured to hold for each relevant LF expression by the premises of every rule whose conclusion requires the normal form of that expression.
Equality for LF expressions also includes conversion, i.e., the congruence generated by the relation that equates and if does not appear free in . The normal forms for the different categories of expressions have the following structure where is an object constant or variable and where the subterms and subtypes appearing in the expression recursively have the same form. We refer to the part corresponding to in a type in this form as its target type and to as its argument types. Let be a variable or constant which appears in the wellformed term and let the number of s that appear in the prefix of its type or kind in beta normal form be . We say is fully applied if every occurrence of in has the form . A type of the form where is fully applied is a base type. We also say that is canonical if it is in normal form and every occurrence of a variable or constant in it is fully applied. It is a known fact that every wellformed LF expression is equal to one in canonical form by virtue of conversion [4]. For the remainder of this paper we will assume all terms are in normal form.
A specification in LF comprises a signature that, as we have seen, identifies a collection of object and type constants. The CurryHoward isomorphism [6] allows types to be interpreted dually as formulas. The dependent nature of the LF type system allows type constants to take objects as arguments. Such constants then correspond to the names of predicates over suitably typed objects. Moreover, the same isomorphism allows object constants, which provide a means for constructing expressions of particular types, to be viewed as the names of parameterized rules for constructing proofs of the relations represented by the types.
Figure 2 presents a concrete signature to illustrate
these ideas.
In showing this and other similar signatures, we use the Twelf syntax
for LF expressions.
In this syntax, is written as and
is written as .
Further, bindings and the corresponding type annotations on variables
are made implicit in situations where the types can be uniquely
inferred; the variables that are implicitly bound are denoted in
Prolog style by tokens that begin with uppercase letters.
The initial part of the signature in Figure 2
defines type and object constants that provide a representation
of the natural numbers and lists of natural numbers.
The signature then identifies a type constant append
that
takes three lists as arguments.
Under the viewpoint just explained, this constant can be interpreted
as a predicate that relates three lists.
Objects of this type can be constructed by using the constants
appnil
and appcons
that are also presented in the
signature.
Viewed differently, these constants name rules that can be used to
construct a proof of the append relation between three lists.
Notice that appcons
requires as an argument an object of
append
type.
This object plays the role of a premise for the rule that
appcons
identifies.
The logic programming use of LF that underlies Twelf consists of presenting a type in the setting of a signature . Such a type corresponds to the request to find an object such that the judgment is derivable. Alternately, a query in Twelf can be seen as the desire to determine the derivability of a formula, the inhabiting term that is found being its proof. The type that is presented as a query may also contain metavariables, denoted by tokens that begin with uppercase letters. In this case, the request is to find substitutions for these variables while simultaneously showing that the instance type is inhabited.
An example of a query relative to the signature in Figure 2 is the following.
append (cons z nil) nil L
An answer to this query is the substitution (cons z nil)
for L
, together with the object
(appcons (cons z nil) nil (cons z nil) (appnil nil))
that inhabits that type. Another query in this setting is
{x:nat} append (cons x nil) (cons z (cons x nil)) (L x).
in which L
is a “higherorder” metavariable of type
nat > list
. The substitution that would be computed by
Twelf for the variable L
in this query is
[y:nat] (cons y (cons z (cons y nil))),
and the corresponding inhabitant or proof term is
[y:nat] appcons nil (cons z (cons y nil)) (cons z (cons y nil)) y (appnil (cons z (cons y nil)))
Notice that the variable x
that is explicitly bound in the
query has a different interpretation from the metavariable
L
.
In particular, it receives a “universal” reading: the query
represents a request to find a value for L
that yields an
inhabited type regardless of what the value of x
is.
Although neither of our example queries exhibited this behavior, the range of an answer substitution may itself contain variables and there may be some residual constraints on these variables presented in the form of a collection of equations between object expressions called “disagreement pairs.” The interpretation of such an answer is that a complete solution can be obtained from the provided substitution by instantiating the remaining variables with closed object expressions that render identical the two sides of each disagreement pair.
3 Logic programming based on
backchain 

where , 
are terms and 
An alternative approach to specifying formal systems is to use a logic in which relationships between terms are encoded in predicates. The idea of animating a specification then corresponds to constructing a proof for a given “goal” formula in the chosen logic. To yield a sensible notion of computation, specifications must also be able to convey information about how a search for a proof should be conducted. Towards this end, we use here the logic of higherorder hereditary Harrop formulas, referred to in short as the logic. This logic underlies the programming language Prolog [8].
The logic is based on Church’s Simple Theory of Types [2]. The expressions of this logic are those of a simply typed calculus (STLC). Types are constructed from the atomic type for propositions and a finite set of other atomic types by using the function type constructor . We assume we have been given a set of variables and a set of constants, each member of these sets being identified together with a type. More complex terms are constructed from these atomic symbols by using application and abstraction in a way that respects the constraints of typing. As in LF, terms differing only in bound variable names are identified. The notion of equality between terms is further enriched by  and conversion. When we orient these rules and think of them as reductions, we are assured in the simply typed setting of the existence of a unique normal form for every wellformed term under these reductions. Thus, equality between two terms becomes the same as the identity of their normal forms. For simplicity, in the remainder of this paper we will assume that all terms have been converted to normal form. We write to denote the capture avoiding substitution of the terms for free occurrences of in .
Logic is introduced into this setting by identifying a subcollection of the set of constants as logical constants and giving them a special meaning. The logical constants that we shall use here are the following: of type of type of type for each type We intend to denote the always true proposition and , which we will write in infix form, to denote implication. The symbol corresponds to the generalized universal quantifier: the usual notation for universal quantification serves as a shorthand for .
To construct a specification within the logic, a user must identify a collection of types and a further set of constants, called nonlogical constants, together with their types. A collection of such associations forms a signature. There is a proviso on the types of nonlogical constants: their argument types must not contain . Nonlogical constants that have as their target or result type correspond to predicate symbols. If is such a constant with the type and are terms of type , respectively, then the term of type constitutes an atomic formula. We shall use the syntax variable to denote such formulas. More complex terms of type are constructed from atomic formulas by using the logical constants. Such terms are also referred to as formulas.
The logic is based on two special classes of formulas identified by the following syntax rules:
We will refer to a formula also as a program clause. Notice that, in elaborated form, such a formula has the structure ; we write here to denote a sequence of universal quantifications.
The computational interpretation of the logic consists of thinking of a collection of formulas as a program and a formula as a goal or query that is to be solved against a given program in the context of a given signature . We represent the judgment that the query has a solution in such a setting by the “sequent” . The rules for deriving such a judgment are shown in Figure 3. Using these rules to search for a derivation leads to a process in which we first simplify a goal in a manner determined by the logical constants that appear in it and then employ program clauses in a familiar backchaining mode to solve the atomic goals that are produced. A property of the logic that should be noted is that both the program and the signature can change in the course of a computation.
We illustrate the use of these ideas in practice by considering, once
again, the encoding of lists of natural numbers and the append
relation on them.
Figure 4 provides both the signature and the program
clauses that are needed for this purpose.
This specification is similar to one that might be provided in Prolog,
except for the use of a curried notation for applications and the fact
that the language is now typed.
We “execute” these specifications by providing a goal formula.
As with Twelf, we will allow goal formulas to contain free or
metavariables for which we intend instantiations to be found through
proof search.
A concrete example of such a goal relative to the specification in
Figure 4 is (append (cons z nil) nil L).
This goal is solvable with the substitution (cons z nil) for L
.
Another example of a query in this setting is
and an answer to this goal is the substitution for L
.
4 Translating Twelf specifications into predicate form
We now turn to the task of animating Twelf specifications using a Prolog implementation. Towards this end, we describe a meaning preserving translation from LF signatures into specifications. Our translation extends the one in [12] by allowing for metavariables in LF expressions. We also present an inverse translation for bringing solutions back from Prolog to the Twelf setting.
The first step in our translation is to map dependently typed lambda expressions into simply typed ones. We shall represent both types and objects in LF by STLC terms (which are also terms), differentiating the two categories by using the (simple) type lfobj for the encodings of LF objects and lftype for those of LF types. To play this out in detail, we first associate an type with each LF type and kind that is given by the mapping shown in Figure 5. Then, corresponding to each object and typelevel LF constant , we identify an constant with the same name but with type . Finally, we transform LF objects and kinds into terms using the mapping in Figure 5.
We would like to consider an inverse to the transformation that we have described above. We have some extra information available in constructing such an inverse: the constants that appear in the terms of interest have their correlates which have been given specific types in the originating LF signature. Even so, the lossy nature of the translation makes the inversion questionable. There are two kinds of problems. First, because (the chosen) simple typing is not sufficiently constraining, we may have wellformed STLC terms for which there is no corresponding LF expression. As a concrete example, consider the following LF signature:
i : type j : type a : i > j c : i
In the encoding we will have the following two constants with associated types:
a : lfobj > lfobj c : lfobj
This means that we can construct the simply typed term
(a (a c))
which cannot be the image of any LF expression that
is wellformed under the given signature.
The second problem is that when an term involves an abstraction,
the choice of LF type to use for for the abstracted variable is
ambiguous.
As a concrete example, consider the term that
has the type lfobj > lfobj
.
This term could map to the LF objects [x:nat] x
and
[x:list] x
, amongst many other choices.
Our solution to these problems is twofold. First, we will assume that we know the type of the LF object that the inversion is to produce; this information will always be available when the terms arise in the course of simulating LF typing derivations using derivations. Second, we will define inversion as a partial function: when we use it to calculate an LF expression from an answer substitution returned by an computation, we will have an additional obligation to show that the inverse must exist.
invvar  invabs 
[10pt] invapp
[10pt]
invconst  invsyn 
The rules in Figure 7 define the inverse transformation. The judgments and are to be derivable when is an term in normal form that inverts to the LF object that has type in a setting where variables and constants are typed according to . The difference between the two judgments is that the first expects as an input whereas the second additionally synthesizes the type. The process starts with checking against an LF type—this type will be available from the original LF query—and it is easily shown that if , then . Notice that we will only ever check an abstraction term against an LF type, ensuring that the type chosen for the bound variable will be unique. We say a substitution is invertible in a given context and signature if each term in its range is invertible in that setting, using the type associated with the domain variable by .
The translation of LF expressions into terms loses all relational information encoded by dependencies in types. For example it transforms the constants encoding the append relation in Figure 2 into the following signature:
append : lfobj > lfobj > lfobj > lftype. appnil : lfobj > lfobj. appcons : lfobj > lfobj > lfobj > lfobj > lfobj > lfobj.
It is no longer possible to construe this as a specification of the append relation between lists. To recover the lost information, we employ a second pass that uses predicates to encode relational content. This pass employs the predicate with type and generates clauses that are such that is derivable from them exactly when is the encoding of an LF term of a base LF type whose encoding is . More specifically, this pass processes each item of the form in the LF signature and produces from it the clause using the rules in Figure 6 that define .
To illustrate the second pass, when used with the signature in
Figure 2, we see that it will produce the following
clauses:
hastype z nat.
x.hastype x nat
hastype (s x) nat.
hastype nil list.
x.(hastype x nat
l.(hastype l list
hastype (cons x l) list)).
l.hastype l list
hastype (appnil l) list.
x.(hastype x nat
l1.(hastype l1 list
l2.(hastype l2 list
l3.(hastype l3 list
a.(hastype a (append l1 l2 l3)
hastype (appcons x l1 l2 l3 a)
(append (cons x l1) l2 (cons x l3))))))).
Contrasting these clauses with the ones of the Prolog program
in Figure 4, we see that it is capable not only of
producing answers to append
queries but also a “proofterm”
that traces the derivation of such queries.
The correctness of our translation is captured by the following theorem (whose proof is currently incomplete). We had said earlier that when looking at terms that are produced by derivations from LF translations, we would have an assurance that these terms are invertible. This is a property that flows, in fact, from the structure of the clauses: as a derivation is constructed, all the substitution terms that are generated are checked to be of the right type using the predicate, and so we will not be able to construct a term which is not invertible.
Theorem 4.1
Let be an LF signature and let be an LF type that possibly contains metavariables.

If Twelf solves the query with the ground answer substitution , then there is an invertible answer substitution for the goal wrt such that the inverse of generalizes (i.e. there exists a such that ).

If is an invertible answer substitution for , then its inverse is an answer substitution for .
Our approach to proving this theorem is to consider the operational semantics of the two systems and to show that derivations in each system can be factored into sequences of steps that can be simulated by the other system. Moreover, this simulation ensures the necessary relationships hold between the answer substitutions that are gradually developed by the derivations in the respective systems.
5 Optimizing the translation
The translation presented in the preceding section does not lend itself well to proof search because it generates a large amount of redundant typing checking. There are many instances when this redundancy can be recognized by a direct analysis of a given Twelf specification: in particular, we can use a structural analysis of an LF expression to determine that a term being substituted for a variable must be of the correct type and hence it is unnecessary to check this explicitly. In this section we develop this idea and present an improved translation. We also discuss another optimization that reflect the types in the Twelf signature more directly into types in . The combination of these optimizations produce clauses that are more compact and that resemble those that might be written in Prolog directly.
We are interested in translating an LF type of the form into an clause that can be used to determine if a type can be viewed as an instance of the target type . This task also requires us to show that are inhabitants of the types ; in the naive translation, this job is done by the formulas pertaining to and that appear in the body of the clause produced for the overall type. However, a particular may occur in in a manner which already makes it clear that the term which replaces it in any instance of must possess such a property. What we want to do, then, is characterize such occurrences of such that we can avoid having to include an inhabitation check in the clause.
We define a strictness condition for variable occurrences and, hence, for variables that possesses this kind of property. By using this condition, we can simplify the translation of a type into an clause without losing accuracy. In addition to efficiency, such a translation also produces a result that bears a much closer resemblance to the LF type from which it originates.
The critical idea behind this criterion is that the path down to the occurrence of is rigid, i.e., it cannot be modified by substitution and is not applied to arguments in a way that could change the structure of the expression substituted for it. We know that the structure will be unchanged by application of arguments by requiring the occurrence of to be applied only to distinct bound variables. Thus we know that any term substituted for has the correct type without needing to explicitly check it. Specifically, we say that the bound variable occurs strictly in the type if it is the case that
holds. We have been able to extend the strictness condition as described in [12] recursively while preserving its utility in recognizing redundancy in type checking. We consider occurrences of bound variables to be strict in the overall type if they are strict in the types of other bound variables that occur strictly in the target type. The relation defined in Figure 8 formalizes this idea.
When is derivable it means that the variable appears strictly in the type in the context . As we work down through the structure of a type we will eventually look at a specific term and a derivation of means that appears strictly in the term . Here, and are both lists of variables where contains the bound variables currently in scope, while contains the quantified variables collected while walking through the type .
Another, more direct, optimization is to reflect the LF types into types in the
simply typed lambda calculus.
Along with this optimization we can also use specialized predicates, rather than
just hastype.
For each LF type we will create a new atomic type utype
in
, as well as a new predicate u
which has the type
> utype > o
.
We then use these to encode the signature in a more natural way.
See Figure 9 for the new translation.
There are now two modes in which translation operates, the negative, , which is essentially the same as before in that it does not check for strictness of bound variables, and the positive, , which will only generate formulas for variables which do not appear strictly. We do this to insure that the eliminations occur in situations in which it makes sense to think of the implication encoding an inhabitation check. We will write for in future to simplify the generated signatures. These optimizations not only clean up the generated signature, but they also improve performance as we have limited the number of clauses which match the head of any given goal formula.
6 An illustration of the translation approach
We illustrate the use of the ideas described in the earlier sections
by considering the append
relation specified in Twelf by the
signature in Figure 2.
The Twelf query that we shall consider is the following that we
previously saw in Section 2:
{x:nat} append (cons x nil) (cons z (cons x nil)) (L x).
This query asks for a substitution for L
that yields an
inhabited type and an object that is a corresponding
inhabitant.
nat : nattype > o.  
list : listtype > o.  
append : listtype > listtype > listtype > appendtype > o.  
nat z.  
x. nat x nat (s x).  
list nil.  
x.(nat x l. list l list (cons x l)).  
l. append nil l l (appcons l).  
xl1l2l3a. append l1 l2 l3 a  
append (cons x l1) l2 (cons x l3) (appcons x l1 l2 l3 a). 
Applying the optimized translation to the signature in
Figure 2 yields the Prolog program shown in
Figure 10.
Further, the Twelf query of interest translates into the goal
formula
x. append (cons x nil) (cons z (cons x nil)) (L x) M.
The answer substitution for this goal in Prolog is
L = y\ cons y (cons z (cons y nil)), M = y\ appcons nil (cons z (cons y nil)) (cons z (cons y nil)) y (appnil (cons z (cons y nil)))
Applying the inverse translation described in
Section 4 to this answer substitution yields the
value for L
and the proof term for the Twelf query that we saw
in Section 2.
7 Conclusion
We have considered in this work an approach to implementing the logic programming treatment of LF specifications that is embodied in Twelf by using the Teyjus implementation of Prolog as a backend. Central to such an implementation is a meaningpreserving translation of Twelf specifications into Prolog programs. The basic structure of such a translation has previously been described by Snow et. al. [12]. Built into that translation is an optimization which takes advantage of statically available type information, quantified through a notion of strictness. In this work we have refined the notion of strictness to potentially enhance the usefulness of this optimization.
To actually use this approach in an implementation of Twelf, it is necessary to also provide a way of translating solutions found by Teyjus into LF terms that constitute answers to the query in LF syntax. Towards this end, we have presented an inverse encoding which describes how to map terms back to LF objects in the context of the original Twelf specification.
The work by Snow et. al. deals only with terms which are closed, and so there had been no treatment for metavariables which may appear in LF expressions. In order to capture the full scope of logic programming in Twelf, we extended the usual presentation of LF to allow for metavariables in terms, and we provided a treatment for such variables in both the derivations and the translation. Although the proof showing the correctness of this translation is still incomplete, we have discussed an approach to developing such a proof that is based on relating the operational semantics of the two systems.
Acknowledgements
This work has been partially supported by the NSF Grant CCF0917140. Opinions, findings, and conclusions or recommendations expressed in this paper are those of the authors and do not necessarily reflect the views of the National Science Foundation.
References
 [1] P. Brisset and O. Ridoux. The compilation of Prolog and its execution with MALI. Publication Interne 687, IRISA, 1992.
 [2] Alonzo Church. A formulation of the simple theory of types. J. of Symbolic Logic, 5:56–68, 1940.
 [3] Amy Felty and Dale Miller. Encoding a dependenttype calculus in a logic programming language. In Mark Stickel, editor, Proceedings of the 1990 Conference on Automated Deduction, volume 449 of LNAI, pages 221–235. Springer, 1990.
 [4] Robert Harper, Furio Honsell, and Gordon Plotkin. A framework for defining logics. Journal of the ACM, 40(1):143–184, 1993.
 [5] Robert Harper and Daniel R. Licata. Mechanizing metatheory in a logical framework. Journal of Functional Programming, 17(4–5):613–673, July 2007.
 [6] William A. Howard. The formulaeastype notion of construction, 1969. In J. P. Seldin and R. Hindley, editors, To H. B. Curry: Essays in Combinatory Logic, Lambda Calculus, and Formalism, pages 479–490. Academic Press, New York, 1980.
 [7] Dale Miller and Gopalan Nadathur. Programming with HigherOrder Logic. Cambridge University Press, June 2012.
 [8] Gopalan Nadathur and Dale Miller. An Overview of Prolog. In Fifth International Logic Programming Conference, pages 810–827, Seattle, August 1988. MIT Press.
 [9] Frank Pfenning. Logic programming in the LF logical framework. In Gérard Huet and Gordon D. Plotkin, editors, Logical Frameworks, pages 149–181. Cambridge University Press, 1991.
 [10] Frank Pfenning and Carsten Schürmann. Twelf User’s Guide, 1.4 edition, December 2002.
 [11] Xiaochu Qi, Andrew Gacek, Steven Holte, Gopalan Nadathur, and Zach Snow. The Teyjus system – version 2, March 2008. http://teyjus.cs.umn.edu/.
 [12] Zachary Snow, David Baelde, and Gopalan Nadathur. A metaprogramming approach to realizing dependently typed logic programming. In ACM SIGPLAN Conference on Principles and Practice of Declarative Programming (PPDP), pages 187–198, 2010.