<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.0 20120330//EN" "JATS-archivearticle1.dtd">
<article xmlns:xlink="http://www.w3.org/1999/xlink">
  <front>
    <journal-meta />
    <article-meta>
      <title-group>
        <article-title>On Type-directed Generation of Lambda Terms</article-title>
      </title-group>
      <contrib-group>
        <contrib contrib-type="author">
          <string-name>PAUL TARAU</string-name>
          <email>tarau@cs.unt.edu</email>
          <xref ref-type="aff" rid="aff0">0</xref>
        </contrib>
        <aff id="aff0">
          <label>0</label>
          <institution>Department of Computer Science and Engineering</institution>
        </aff>
      </contrib-group>
      <pub-date>
        <year>2015</year>
      </pub-date>
      <history>
        <date date-type="accepted">
          <day>5</day>
          <month>6</month>
          <year>2015</year>
        </date>
      </history>
      <abstract>
        <p>We describe a Prolog-based combined lambda term generator and type-inferrer for closed well-typed terms of a given size, in de Bruijn notation. By taking advantage of Prolog's unique bidirectional execution model and sound unification algorithm, our generator can build “customized” closed terms of a given type. This relational view of terms and their types enables the discovery of interesting patterns about frequently used type expressions occurring in well-typed functional programs. Our study uncovers the most “popular” types that govern function applications among a about a million small-sized lambda terms and hints toward practical uses to combinatorial software testing. It also shows the effectiveness of Prolog as a meta-language for modeling properties of lambda terms and their types.</p>
      </abstract>
      <kwd-group>
        <kwd>lambda calculus</kwd>
        <kwd>de Bruijn notation</kwd>
        <kwd>type inference</kwd>
        <kwd>generation of lambda terms</kwd>
        <kwd>logic programming as a meta-language</kwd>
      </kwd-group>
    </article-meta>
  </front>
  <body>
    <sec id="sec-1">
      <title>1 Introduction</title>
      <p>
        Properties of logic variables, unification with occurs-check and exploration of solution
spaces via backtracking facilitate compact algorithms for inferring types or generate terms
for various calculi. This holds in particular for lambda terms
        <xref ref-type="bibr" rid="ref1">(Barendregt 1984)</xref>
        . Lambda
terms provide a foundation to modern functional languages, type theory and proof
assistants and have been lately incorporated into mainstream programming languages including
Java 8, C# and Apple’s Swift.
      </p>
      <p>While possibly one of the most heavily researched computational objects, lambda terms
offer an endless stream of surprises to anyone digging just deep enough below their
intriguingly simple surface.</p>
      <p>
        This paper focuses on the synergy between combinatorial generation of lambda terms
and type inference, both favored by the use of Prolog as meta-language for representing
them. While we will take advantage of Prolog’s logic variables for type inference, we will
retain the “nameless” de Bruijn representation
        <xref ref-type="bibr" rid="ref6">(de Bruijn 1972)</xref>
        for term generation as it
provides a canonical representation to a -equivalent terms. We will also focus on closed
terms (terms without free variables) as they are the ones used in lambda calculus based
programming languages like Haskell and ML or proof assistants like Coq or Agda.
      </p>
      <p>Prolog’s ability to support “relational” queries enables us to easily explore the population
of de Bruijn terms up to a given size and answer questions like the following:
1. How many distinct types occur for terms up to a given size?
2. What are the most popular types?
3. What are the terms that share a given type?
4. What is the smallest term that has a given type?
5. What smaller terms have the same type as this term?</p>
      <p>The paper is organized as follows. Section 2 introduces the de Bruijn notation for lambda
terms and describes a type inference algorithm working on them. Section 3 introduces a
generator for lambda terms in de Bruijn form. Section 4 introduces an algorithm combining
term generation and type inference. Section 5 uses our combined term generation and type
inference algorithm to discover frequently occurring type patterns. Section 6 describes
a type-directed algorithm for the generation of closed typable lambda terms. Section 7
discusses related work and section 8 concludes the paper.</p>
      <p>The paper is structured as a literate Prolog program. The code, tested with SWI-Prolog
6.6.6 and YAP 6.3.4., is at http://www.cse.unt.edu/~tarau/research/2015/dbt.pro.</p>
    </sec>
    <sec id="sec-2">
      <title>2 Type inference for lambda terms in de Bruijn notation</title>
      <p>
        As lambda terms represent functions, inferring their types provides information on what
kind of argument(s) they can be applied to. For simple types, type inference is decidable
        <xref ref-type="bibr" rid="ref11">(Hindley and Seldin 2008)</xref>
        and it uses unification to recursively propagate type information
between application sites of variable occurrences covered by a given lambda binder. We
will describe next a type inference algorithm using de Bruijn indices in Prolog - a somewhat
unusual choice, given that logic variables can play the role of lambda binders directly. One
of the reasons we chose them is that they will be simpler to manipulate at meta-language
level, as they handle object-level variables implicitly. At the same time this might be useful
for other purposes, as we are not aware of any Prolog implementation of type inference
with this representation of lambda terms.
      </p>
      <sec id="sec-2-1">
        <title>2.1 De Bruijn Indices</title>
        <p>
          De Bruijn indices
          <xref ref-type="bibr" rid="ref6">(de Bruijn 1972)</xref>
          provide a name-free representation of lambda terms.
All closed terms that can be transformed by a renaming of variables (a-conversion) will
share a unique representation. Variables following lambda abstractions are omitted and
their occurrences are marked with positive integers counting the number of lambdas until
the one binding them is found on the way up to the root of the term. We represent them
using the constructor a/2 for application, l/1 for lambda abstractions (that we will call
shortly binders) and v/1 for marking the integers corresponding to the de Bruijn indices.
        </p>
        <p>For instance, the term l(A,a(l(B,a(A,a(B,B))),l(C,a(A,a(C,C))))) is
represented as l(a(l(a(v(1),a(v(0),v(0)))),l(a(v(1),a(v(0),v(0)))))), given that
v(1) is bound by the outermost lambda (two steps away, counting from 0) and the
occurrences of v(0) are bound each by the closest lambda, represented by the constructor l/1.</p>
        <p>One can define the size of a lambda expression in de Bruijn form as the number of its
internal nodes, as implemented by the predicate dbTermSize.
dbTermSize(v(_),0).
isClosed(T):-isClosed1(T,0).
isClosed1(v(N),D):-N&lt;D.
isClosed1(l(A),D):-D1 is D+1,</p>
        <p>isClosed1(A,D1).
isClosed1(a(X,Y),D):isClosed1(X,D),
isClosed1(Y,D).</p>
        <p>A lambda term is called closed if it contains no free variables. The predicate isClosed
defines this property for de Bruijn terms.</p>
        <p>Besides being closed, lambda terms interesting for functional languages and proof
assistants, are also well-typed. We will start with an algorithm inferring types directly on the
de Bruijn terms.</p>
      </sec>
      <sec id="sec-2-2">
        <title>2.2 A type inference algorithm for Bruijn terms</title>
        <p>
          Simple types will be defined here also as binary trees built with the constructor “-&gt;/2” with
empty leaves, representing the unique primitive type “o”. Types can be seen as as a “binary
tree approximation” of lambda terms, centered around ensuring their safe and terminating
evaluation (strong normalization), as it is well-known (e.g.,
          <xref ref-type="bibr" rid="ref2">(Barendregt 1991)</xref>
          ) that lambda
terms that have simple types are strongly normalizing. When a term X has a type T we say
that the type T is inhabited by the term X.
        </p>
        <p>
          While in a functional language inferring types requires implementing unification with
occur check, as shown for instance in the appendix of
          <xref ref-type="bibr" rid="ref10 ref9">(Grygiel and Lescanne 2013)</xref>
          , this is
readily available in Prolog.
        </p>
        <p>The predicate boundTypeOf/3 works by associating the same logical variable, denoting
its type, to each of its occurrences. As a unique logic variable is associated to each leaf v/1
corresponding via its de Bruijn index to the same binder, types are consistently inferred.
This is ensured by the use of the built-in nth0(I,Vs,V0) that unifies V0 with the I-th
element of the type context Vs. Note that unification with occurs-check needs to be used to
avoid cycles in the inferred type formulas.
boundTypeOf(v(I),V,Vs):nth0(I,Vs,V0),
unify_with_occurs_check(V,V0).
boundTypeOf(a(A,B),Y,Vs):boundTypeOf(A,(X-&gt;Y),Vs),
boundTypeOf(B,X,Vs).
boundTypeOf(l(A),(X-&gt;Y),Vs):</p>
        <p>boundTypeOf(A,Y,[X|Vs]).</p>
        <p>At this point, most general types are inferred by boundTypeOf as fresh variables, similar
to polymorphic types in functional languages, if one interprets logic variables as
universally quantified.</p>
        <sec id="sec-2-2-1">
          <title>Example 1</title>
          <p>Type inferred for the S combinator l x0: l x1: l x2:((x0 x2) (x1 x4)) in de Bruijn form.
?- X=l(l(l(a(a(v(2), v(0)), a(v(1), v(0)))))),boundTypeOf(X,T,0).
X = l(l(l(a(a(v(2), v(0)), a(v(1), v(0)))))),
T = ((A-&gt;B-&gt;C)-&gt; (A-&gt;B)-&gt;A-&gt;C).</p>
          <p>However, as we are only interested in simple types of closed terms with only one basic
type, we will bind uniformly the leaves of our type tree to the constant “o” representing
our only primitive type, by using the predicate bindType/1.
boundTypeOf(A,T):-boundTypeOf(A,T0,[]),bindType(T0),!,T=T0.
bindType(o):-!.
bindType((A-&gt;B)):bindType(A),
bindType(B).</p>
        </sec>
        <sec id="sec-2-2-2">
          <title>Example 2</title>
          <p>Simple type inferred for the S combinator and failure to assign a type to the Y combinator
l x0:( l x1:(x0 (x1 x2)) l x2:(x1 (x2 x2))).
?- boundTypeOf(l(l(l(a(a(v(2), v(0)), a(v(1), v(0)))))),T).</p>
          <p>T = ((o-&gt; (o-&gt;o))-&gt; ((o-&gt;o)-&gt; (o-&gt;o))).
?- boundTypeOf(l(a(l(a(v(1), a(v(0), v(0)))),</p>
          <p>l(a(v(1), a(v(0), v(0)))))),T).
false.</p>
        </sec>
      </sec>
    </sec>
    <sec id="sec-3">
      <title>3 Deriving a generator for lambda terms in de Bruijn form</title>
      <sec id="sec-3-1">
        <title>3.1 Generation of de Bruijn terms</title>
        <p>We can derive a generator for closed lambda terms in de Bruijn form by extending a
Motzkin or unary-binary tree generator to keep track of the lambda binders. When reaching
a leaf v/1, one of the available binders (expressed as a de Bruijn index) will be assigned
to it nondeterministically.</p>
        <p>
          The predicate genDBterm/4 generates closed de Bruijn terms with a fixed number of
internal (non-index) nodes, as counted by entry A220894 in
          <xref ref-type="bibr" rid="ref14">(Sloane 2014)</xref>
          .
genDBterm(v(X),V)--&gt;
{down(V,V0)},
{between(0,V0,X)}.
genDBterm(l(A),V)--&gt;down,
{up(V,NewV)},
genDBterm(A,NewV).
genDBterm(a(A,B),V)--&gt;down,
genDBterm(A,V),
genDBterm(B,V).
up(K1,K2):-K2 is K1+1.
        </p>
        <p>The range of possible indices is provided by Prolog’s built-in integer range generator
between/3, that provides values from 0 to V0. Note also the use of down/2
abstracting away the predecessor operation and up/2 abstracting away the successor operation.
Together, they control the amount of available nodes and the incrementing of de Bruijn
indices at each lambda node.</p>
        <p>Our generator of de Bruijn terms is exposed through two interfaces: genDBterm/2 that
generates closed de Bruijn terms with exactly L non-index nodes and genDBterms/2 that
generates terms with up to L non-index nodes, by not enforcing that exactly L internal
nodes must be used.
genDBterm(L,T):-genDBterm(T,0,L,0).
genDBterms(L,T):-genDBterm(T,0,L,_).</p>
        <p>
          Inserting a down operation in the first clause of genDBterm/4 will enumerate terms counted
by sequence A135501 instead of A220894, as this would imply assuming size 1 for
variables. in
          <xref ref-type="bibr" rid="ref14">(Sloane 2014)</xref>
          .
        </p>
        <sec id="sec-3-1-1">
          <title>Example 3</title>
          <p>Generation of terms with up to 2 internal nodes.
?- genDBterms(2,T).</p>
          <p>T = l(v(0)) ;
T = l(l(v(0))) ;
T = l(l(v(1))) ;
T = l(a(v(0), v(0))).</p>
        </sec>
      </sec>
    </sec>
    <sec id="sec-4">
      <title>4 Combining term generation and type inference</title>
      <p>One could combine a generator for closed terms and a type inferrer in a “generate-and-test”
style as follows:
genTypedTerm1(L,Term,Type):genDBterm(L,Term),
boundTypeOf(Term,Type).</p>
      <p>Note that when one wants to select only terms having a given type this is quite inefficient.
Next, we will show how to combine size-bound term generation, testing for closed terms
and type inference into a single predicate. This will enable efficient querying about what
terms inhabit a given type, as one would expect from Prolog’s multi-directional execution
model.</p>
      <sec id="sec-4-1">
        <title>4.1 Generating closed well-typed terms of a given size</title>
        <p>One can derive, from the type inferrer boundTypeOf, a more efficient generator for de
Bruijn terms with a given number of internal nodes.</p>
        <p>The predicate genTypedTerm/5 relies on Prolog’s DCG notation to thread together the
steps controlled by the predicate down. Note also the nondeterministic use of the built-in
nth0 that enumerates values for both I and V ranging over the list of available variables Vs,
as well as the use of unify with occurs check to ensure that unification of candidate
types does not create cycles.
genTypedTerm(v(I),V,Vs)--&gt;
{
nth0(I,Vs,V0),
unify_with_occurs_check(V,V0)
}.
genTypedTerm(a(A,B),Y,Vs)--&gt;down,
genTypedTerm(A,(X-&gt;Y),Vs),
genTypedTerm(B,X,Vs).
genTypedTerm(l(A),(X-&gt;Y),Vs)--&gt;down,</p>
        <p>genTypedTerm(A,Y,[X|Vs]).
genTypedTerm(L,B,T):genTypedTerm(B,T,[],L,0),
bindType(T).
genTypedTerms(L,B,T):genTypedTerm(B,T,[],L,_),
bindType(T).</p>
        <p>
          Two interfaces are offered: genTypedTerm that generates de Bruijn terms of with exactly
L internal nodes and genTypedTerms that generates terms with L internal nodes or less.
As expected, the number of solutions, computed as the sequence 1, 2, 9, 40, 238, 1564,
11807, 98529, 904318, 9006364, 96709332, 1110858977 : : : for sizes 1; 2; 3; : : : ,12, : : :
matches entry A220471 in
          <xref ref-type="bibr" rid="ref14">(Sloane 2014)</xref>
          . Note that the last 2 terms are not (yet) in the
A220471 in
          <xref ref-type="bibr" rid="ref14">(Sloane 2014)</xref>
          as the generate and filter method used in
          <xref ref-type="bibr" rid="ref10 ref9">(Grygiel and Lescanne
2013)</xref>
          is limited by the super-exponential growth of the closed lambda terms among which
the relatively few well-typed ones need to be found (e.g. more than 12 billion terms for
size 12). Interestingly, by interleaving generation of closed terms and type inference in the
predicate genTypedTerm the time to generate all the well-typed terms is actually shorter
than the time to generate all closed terms of the same size, e.g.. 3.2 vs 4.3 seconds for
size 9 with SWI-Prolog. As via the Curry-Howard isomorphism closed simply typed terms
correspond to proofs of tautologies in minimal logic, co-generation of terms and types
corresponds to co-generation of tautologies and their proofs for proofs of given length.
        </p>
        <sec id="sec-4-1-1">
          <title>Example 4</title>
          <p>Generation of well-typed closed de Bruijn terms of size 3.
?- genTypedTerm(3,Term,Type).</p>
          <p>Term = a(l(v(0)), l(v(0))),Type = (o-&gt;o) ;
Term = l(a(v(0), l(v(0)))),Type = (((o-&gt;o)-&gt;o)-&gt;o) ;
Term = l(a(l(v(0)), v(0))),Type = (o-&gt;o) ;
Term = l(a(l(v(1)), v(0))),Type = (o-&gt;o) ;
Term = l(l(a(v(0), v(1)))),Type = (o-&gt; ((o-&gt;o)-&gt;o)) ;
Term = l(l(a(v(1), v(0)))),Type = ((o-&gt;o)-&gt; (o-&gt;o)) ;
Term = l(l(l(v(0)))),Type = (o-&gt; (o-&gt; (o-&gt;o))) ;
Term = l(l(l(v(1)))),Type = (o-&gt; (o-&gt; (o-&gt;o))) ;
Term = l(l(l(v(2)))),Type = (o-&gt; (o-&gt; (o-&gt;o))) .
Size
1
2
3
4
5
6
7
8
9</p>
        </sec>
      </sec>
      <sec id="sec-4-2">
        <title>4.2 Querying the generator for specific types</title>
        <p>Coming with Prolog’s unification and non-deterministic search, is the ability to make more
specific queries by providing a type pattern, that selects only terms that match it, while
generating terms and inferring their types.</p>
        <p>The predicate queryTypedTerm finds closed terms of a given type of size exactly L.
queryTypedTerm(L,QueryType,Term):genTypedTerm(L,Term,QueryType),
boundTypeOf(Term,QueryType).</p>
        <p>Similarly, the predicate queryTypedTerm finds closed terms of a given type of size L or
less.
queryTypedTerms(L,QueryType,Term):genTypedTerms(L,Term,QueryType),
boundTypeOf(Term,QueryType).</p>
        <p>Note that giving the query type ahead of executing genTypedTerm would unify with more
general “false positives”, as type checking, contrary to type synthesis, proceeds bottom-up.
This justifies filtering out the false positives simply by testing with the deterministic
predicate boundTypeOf at the end. Despite the extra call to boundTypeOf, the performance
improvements are significant, as shown in Figure 1. The figure also shows that when the slow
generate-and-test predicate genTypedTerm1 is used, the result (in
“logical-inferences-persecond”) does not depend on the pattern, contrary to the fast queryTypedTerm that prunes
mismatching types while inferring the type of the terms as it generates them.</p>
        <sec id="sec-4-2-1">
          <title>Example 5</title>
          <p>Terms of type o-&gt;o of size 4.
?- queryTypedTerm(3,(o-&gt;o),Term).</p>
          <p>Term = a(l(v(0)), l(v(0))) ;
Term = l(a(l(v(0)), v(0))) ;
Term = l(a(l(v(1)), v(0))) .
?- queryTypedTerms(12,(o-&gt;o)-&gt;o,T).
false.</p>
          <p>Note that the last query, taking about a minute, shows that no closed terms of type (o-&gt;o)-&gt;o
exist up to size 12. In fact, it is known that no such terms exist, as the corresponding logic
formula is not a tautology in minimal logic.</p>
        </sec>
      </sec>
      <sec id="sec-4-3">
        <title>4.3 Same-type siblings</title>
        <p>Given a closed well-typed lambda term, we can ask what other terms of the same size or
smaller share the same type. This can be interesting for finding possibly alternative
implementations of a given function or for generation of similar siblings in genetic programming.</p>
        <p>The predicate typeSiblingOf lists all the terms of the same or smaller size having the
same type as a given term.
typeSiblingOf(Term,Sibling):dbTermSize(Term,L),
boundTypeOf(Term,Type),
queryTypedTerms(L,Type,Sibling).</p>
        <sec id="sec-4-3-1">
          <title>Example 6</title>
          <p>?- typeSiblingOf(l(l(a(v(0),a(v(0),v(1))))),T).
T = l(l(a(v(0), v(1)))) ; % &lt;= smaller sibling
T = l(l(a(v(0), a(v(0), v(1))))) .</p>
        </sec>
      </sec>
    </sec>
    <sec id="sec-5">
      <title>5 Discovering frequently occurring type patterns</title>
      <p>The ability to run “relational queries” about terms and their types extends to compute
interesting statistics, giving a glimpse at their distribution.</p>
      <sec id="sec-5-1">
        <title>5.1 The “Popular” type patterns</title>
        <p>
          As types can be seen as an approximation of their inhabitants, we expect them to be shared
among distinct terms. As we can enumerate all the terms for small sizes and infer their
types, we would like to know what are the most frequently occurring ones. This can be
meaningful as a comparison base for types that are used in human-written programs of
comparable size. In approaches like
          <xref ref-type="bibr" rid="ref13">(Palka et al. 2011)</xref>
          , where types are used to direct the
generation of random terms, focusing on the most frequent types might help with
generation of more realistic random tests.
        </p>
        <p>Figure 2 describes counts for terms and their types for small sizes. It also shows the first
two most frequent types with the count of terms they apply to.</p>
        <p>Figure 3 shows the “most popular types” for the about 1 million closed well-typed terms
up to size 9 and the count of their inhabitants.</p>
        <p>We can observe that, like in some human-written programs, functions representing
binary operations of type o-&gt;o-&gt;o are the most popular. Ternary operations o-&gt;o-&gt;o-&gt;o
come third and unary operations o-&gt;o come fourth. Somewhat surprisingly, a higher order
function type (o-&gt;o)-&gt;o-&gt;o applying a function to an argument to return a result comes
second and multi-argument variants of it are also among the top 10.
Term size
1
2
3
4
5
6
7
8
9</p>
      </sec>
      <sec id="sec-5-2">
        <title>5.2 Growth sequences of some popular types</title>
        <p>We can make use of our generator’s efficient specialization to a given type to explore
empirical estimates for some types interesting to human programmers.</p>
        <p>Contrary to the total absence of the type (o-&gt;o)-&gt;o among terms of size up to 12,
“binary operations” of type o-&gt;(o-&gt;o) turn out to be quite frequent, giving, by increasing
sizes, the sequence [0, 2, 0, 14, 12, 201, 445, 4632, 17789, 158271, 891635].</p>
        <p>
          Transformers of type o-&gt;o, by increasing sizes, give the sequence [1, 0, 3, 3, 31, 78,
596, 2500, 18474, 110265]. While type (o-&gt;o)-&gt;o turns our to be absent up to size 12,
the type (o-&gt;o)-&gt;(o-&gt;o), describing transformers of transformers turns out to be quite
popular, as shown by the sequence [0, 0, 1, 1, 18, 52, 503, 2381, 19855, 125599]. The same
turns out to be true also for (o-&gt;o)-&gt;((o-&gt;o)-&gt;(o-&gt;o)), giving [0, 0, 0, 0, 2, 6, 96, 505,
5287, 36769] and ((o-&gt;o)-&gt;(o-&gt;o)) -&gt; ((o-&gt;o)-&gt;(o-&gt;o)) giving [0, 0, 0, 0, 0, 6,
23, 432, 2450, 29924]. One might speculate that homotopy type theory
          <xref ref-type="bibr" rid="ref17">(The Univalent
Foundations Program 2013)</xref>
          , that focuses on such transformations and transformations of
transformations etc. has a rich population of lambda terms from which to chose interesting
inhabitants of such types!
        </p>
        <p>Another interface, generating closed simply-typed terms of a given size, restricted to
have at most a given number of free de Bruijn indices, is implemented by the predicate
genTypedWithSomeFree.
genTypedWithSomeFree(Size,NbFree,B,T):between(0,NbFree,NbVs),
length(FreeVs,NbVs),
genTypedTerm(B,T,FreeVs,Size,0),
bindType(T).</p>
        <p>
          The first 9 numbers counting closed simply-typed terms with at most one free variable (not
yet in
          <xref ref-type="bibr" rid="ref14">(Sloane 2014)</xref>
          ), are [3, 10, 45, 256, 1688, 12671, 105743, 969032, 9639606].
        </p>
        <p>Note that, as our generator performs the early pruning of untypable terms, rather than as
a post-processing step, enumeration and counting of these terms happens in a few seconds.</p>
      </sec>
    </sec>
    <sec id="sec-6">
      <title>6 Generating closed typable lambda terms by types</title>
      <p>
        In
        <xref ref-type="bibr" rid="ref13">(Palka et al. 2011)</xref>
        a “type-directed” mechanism for the generation of random terms is
introduced, resulting in more realistic (while not uniformly random) terms, used
successfully in discovering some GHC bugs.
      </p>
      <p>We can organize in a similar way the interface of our combined generator and type
inferrer.</p>
      <sec id="sec-6-1">
        <title>6.1 Generating type trees</title>
        <p>The predicate genType generates binary trees representing simple types with a single base
type ``o''.</p>
        <p>It provides two interfaces, for generating types of exactly size N or up to size N.
genType(o)--&gt;[].
genType((X-&gt;Y))--&gt;down,
genType(X),
genType(Y).
genType(N,X):-genType(X,N,0).
genTypes(N,X):-genType(X,N,_).</p>
        <sec id="sec-6-1-1">
          <title>Example 7</title>
          <p>Type trees with up to 2 internal nodes (and up to 4 leaves).
?- genTypes(3,T).
?- genTypes(2,T).</p>
          <p>T = o ;
T = (o-&gt;o) ;
T = (o-&gt;o-&gt;o) ;
T = ((o-&gt;o)-&gt;o) .</p>
          <p>Next, we will combine this type generator with the generator that efficiently produces terms
matching each type pattern.</p>
        </sec>
      </sec>
      <sec id="sec-6-2">
        <title>6.2 Generating lambda terms by increasing type sizes</title>
        <p>The predicate genByType first generates types (seen simply as binary trees) with genType
and then uses the unification-based querying mechanism to generate all closed well-typed
de Bruijn terms with fewer internal nodes then their binary tree type.
genByType(L,B,T):genType(L,T),
queryTypedTerms(L,T,B).</p>
        <sec id="sec-6-2-1">
          <title>Example 8</title>
          <p>Enumeration of closed simply-typed de Bruijn terms with types of size 3 and terms of a
given type with at most 3 internal nodes.
?- genByType(3,B,T).</p>
          <p>B = l(l(l(v(0)))),T = (o-&gt;o-&gt;o-&gt;o) ;
B = l(l(l(v(1)))),T = (o-&gt;o-&gt;o-&gt;o) ;
B = l(l(l(v(2)))),T = (o-&gt;o-&gt;o-&gt;o) ;
B = l(l(a(v(0), v(1)))),T = (o-&gt; (o-&gt;o)-&gt;o) ;
B = l(l(a(v(1), v(0)))),T = ((o-&gt;o)-&gt;o-&gt;o) ;
B = l(a(v(0), l(v(0)))),T = (((o-&gt;o)-&gt;o)-&gt;o) .</p>
          <p>Given that various constraints are naturally interleaved by our generator we obtain in a
few seconds the sequence counting these terms having types up to size 8, [1, 2, 6, 18, 84,
376, 2344, 15327]. Intuitively this means that despite of their growing sizes, types have an
increasingly large number of inhabitants of sizes smaller than their size. This is somewhat
contrary to what we see in human-written code, where types are almost always simpler and
smaller than the programs inhabiting them.</p>
        </sec>
      </sec>
    </sec>
    <sec id="sec-7">
      <title>7 Related work</title>
      <p>
        The classic reference for lambda calculus is
        <xref ref-type="bibr" rid="ref1">(Barendregt 1984)</xref>
        . Various instances of typed
lambda calculi are overviewed in
        <xref ref-type="bibr" rid="ref2">(Barendregt 1991)</xref>
        .
      </p>
      <p>
        Originally introduced in
        <xref ref-type="bibr" rid="ref6">(de Bruijn 1972)</xref>
        , the de Bruijn notation makes terms equivalent
up to a-conversion and facilitates their normalization
        <xref ref-type="bibr" rid="ref12">(Kamareddine 2001)</xref>
        .
      </p>
      <p>
        Combinatorics of lambda terms, including enumeration, random generation and
asymptotic behavior has seen an increased interest recently (see for instance
        <xref ref-type="bibr" rid="ref10 ref10 ref3 ref4 ref5 ref9 ref9">(David et al. 2009;
Bodini et al. 2011; Grygiel and Lescanne 2013; David et al. 2010; Grygiel et al. 2013)</xref>
        ),
partly motivated by applications to software testing, given the widespread use of lambda
terms as an intermediate language in compilers for functional languages and proof
assistants. In
        <xref ref-type="bibr" rid="ref13 ref7">(Palka et al. 2011; Fetscher et al. 2015)</xref>
        , types are used to generate random terms
for software testing. The same naturally “goal-oriented” effect is obtained in the
generator/type inferrer for de Bruijn terms in subsection 4.2, by taking advantage of Prolog’s ability
to backtrack over possible terms, while filtering against unification with a specific pattern.
In
        <xref ref-type="bibr" rid="ref15 ref16 ref7">(Tarau 2015b)</xref>
        generation algorithms for several sub-families of lambda terms are given
as well as a compressed deBruijn representation is introduced. In
        <xref ref-type="bibr" rid="ref15 ref16">(Tarau 2015a)</xref>
        Rosser’s
X-combinator trees
        <xref ref-type="bibr" rid="ref8">(Fokker 1992)</xref>
        are used as a uniform representation via bijections top
lambda terms in de Bruijn notation, types and a tree-based number representation.
      </p>
      <p>
        Of particular interest are the results of
        <xref ref-type="bibr" rid="ref10 ref9">(Grygiel and Lescanne 2013)</xref>
        where recurrence
relations and asymptotic behavior are studied for several families of lambda terms.
Empirical evaluation of the density of closed simply-typed general lambda terms described
in
        <xref ref-type="bibr" rid="ref10 ref9">(Grygiel and Lescanne 2013)</xref>
        indicates extreme sparsity for large sizes. However, the
problem of their exact asymptotic behavior is still open.
      </p>
    </sec>
    <sec id="sec-8">
      <title>8 Conclusions</title>
      <p>We have described Prolog-based term and type generation and as well as type-inference
algorithms for de Bruijn terms. Among the possible applications of our techniques we
mention compilation and test generation for lambda-calculus based languages and proof
assistants.</p>
      <p>By taking advantage of Prolog’s unique bidirectional execution model and unification
algorithm (including support for cyclic terms and occurs-check), we have merged
generation and type inference in an algorithm that can build “customized closed terms of a
given type”. This “relational view” of terms and their types has enabled the discovery of
interesting patterns about the type expressions occurring in well-typed programs. We have
uncovered the most “popular” types that govern function applications among a about a
million small-sized lambda terms.</p>
      <p>The paper has also introduced a number of algorithms that, at our best knowledge, are
novel, at least in terms of their logic programming implementation, among which we
mention the type inference for de Bruijn terms using unification with occurs-check in
subsection 2.2 and the integrated generation and type inference algorithm for closed simply
typed de Bruijn terms in section 4. Besides the ability to efficiently query for inhabitants
of specific types, our algorithms also support a from of “query-by-example” mechanism,
for finding (possibly smaller) terms inhabiting the same type as the query term.</p>
      <p>We have also observed some interesting phenomena about frequently occurring types,
that seem to be similar to those in human-written programs and we have computed growth
sequences for the number of inhabitants of some “popular” types, for which we have not
found any study in the literature.</p>
      <p>While a non-strict functional language like Haskell could have been used for deriving
similar algorithms, the synergy between Prolog’s non-determinism, DCG transformation
and the availability of unification with occurs-check made the code embedded in the paper
significantly simpler and arguably clearer.</p>
    </sec>
    <sec id="sec-9">
      <title>Acknowledgement</title>
      <p>This research has been supported by NSF grant 1423324.</p>
    </sec>
  </body>
  <back>
    <ref-list>
      <ref id="ref1">
        <mixed-citation>
          <string-name>
            <surname>BARENDREGT</surname>
            ,
            <given-names>H. P.</given-names>
          </string-name>
          <year>1984</year>
          .
          <article-title>The Lambda Calculus Its Syntax and Semantics</article-title>
          , Revised ed. Vol.
          <volume>103</volume>
          . North Holland.
        </mixed-citation>
      </ref>
      <ref id="ref2">
        <mixed-citation>
          <string-name>
            <surname>BARENDREGT</surname>
            ,
            <given-names>H. P.</given-names>
          </string-name>
          <year>1991</year>
          .
          <article-title>Lambda calculi with types</article-title>
          .
          <source>In Handbook of Logic in Computer Science</source>
          . Vol.
          <volume>2</volume>
          . Oxford University Press.
        </mixed-citation>
      </ref>
      <ref id="ref3">
        <mixed-citation>
          <string-name>
            <surname>BODINI</surname>
            ,
            <given-names>O.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>GARDY</surname>
            ,
            <given-names>D.</given-names>
          </string-name>
          , AND GITTENBERGER,
          <string-name>
            <surname>B.</surname>
          </string-name>
          <year>2011</year>
          .
          <article-title>Lambda-terms of bounded unary height</article-title>
          .
          <source>In ANALCO. SIAM</source>
          ,
          <fpage>23</fpage>
          -
          <lpage>32</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref4">
        <mixed-citation>
          <string-name>
            <surname>DAVID</surname>
            ,
            <given-names>R.</given-names>
          </string-name>
          , GRYGIEL,
          <string-name>
            <given-names>K.</given-names>
            ,
            <surname>KOZIK</surname>
          </string-name>
          ,
          <string-name>
            <surname>J.</surname>
          </string-name>
          , RAFFALLI,
          <string-name>
            <given-names>C.</given-names>
            ,
            <surname>THEYSSIER</surname>
          </string-name>
          ,
          <string-name>
            <surname>G.</surname>
          </string-name>
          , AND ZAIONC,
          <string-name>
            <surname>M.</surname>
          </string-name>
          <year>2010</year>
          .
          <article-title>Asymptotically almost all l -terms are strongly normalizing</article-title>
          .
          <source>Preprint: arXiv: math. LO/0903.5505 v3.</source>
        </mixed-citation>
      </ref>
      <ref id="ref5">
        <mixed-citation>
          <string-name>
            <surname>DAVID</surname>
            ,
            <given-names>R.</given-names>
          </string-name>
          , RAFFALLI,
          <string-name>
            <given-names>C.</given-names>
            ,
            <surname>THEYSSIER</surname>
          </string-name>
          ,
          <string-name>
            <surname>G.</surname>
          </string-name>
          , GRYGIEL,
          <string-name>
            <given-names>K.</given-names>
            ,
            <surname>KOZIK</surname>
          </string-name>
          ,
          <string-name>
            <surname>J.</surname>
          </string-name>
          , AND ZAIONC,
          <string-name>
            <surname>M.</surname>
          </string-name>
          <year>2009</year>
          .
          <article-title>Some properties of random lambda terms</article-title>
          .
          <source>Logical Methods in Computer Science</source>
          <volume>9</volume>
          ,
          <fpage>1</fpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref6">
        <mixed-citation>
          <string-name>
            <surname>DE BRUIJN</surname>
            ,
            <given-names>N. G.</given-names>
          </string-name>
          <year>1972</year>
          .
          <article-title>Lambda calculus notation with nameless dummies, a tool for automatic formula manipulation, with application to the Church-Rosser Theorem</article-title>
          .
          <source>Indagationes Mathematicae</source>
          <volume>34</volume>
          ,
          <fpage>381</fpage>
          -
          <lpage>392</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref7">
        <mixed-citation>
          <string-name>
            <surname>FETSCHER</surname>
            ,
            <given-names>B.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>CLAESSEN</surname>
            ,
            <given-names>K.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>PALKA</surname>
            ,
            <given-names>M. H.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>HUGHES</surname>
          </string-name>
          ,
          <string-name>
            <surname>J.</surname>
          </string-name>
          ,
          <string-name>
            <surname>AND FINDLER</surname>
          </string-name>
          ,
          <string-name>
            <surname>R. B.</surname>
          </string-name>
          <year>2015</year>
          .
          <article-title>Making random judgments: Automatically generating well-typed terms from the definition of a typesystem</article-title>
          .
          <source>In Programming Languages and Systems - 24th European Symposium on Programming, ESOP</source>
          <year>2015</year>
          ,
          <article-title>Held as Part of the European Joint Conferences on Theory and Practice of Software</article-title>
          ,
          <source>ETAPS</source>
          <year>2015</year>
          , London, UK, April
          <volume>11</volume>
          -
          <issue>18</issue>
          ,
          <year>2015</year>
          . Proceedings.
          <volume>383</volume>
          -
          <fpage>405</fpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref8">
        <mixed-citation>
          <string-name>
            <surname>FOKKER</surname>
            ,
            <given-names>J.</given-names>
          </string-name>
          <year>1992</year>
          .
          <article-title>The systematic construction of a one-combinator basis for lambda-terms</article-title>
          .
          <source>Formal Aspects of Computing</source>
          <volume>4</volume>
          ,
          <fpage>776</fpage>
          -
          <lpage>780</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref9">
        <mixed-citation>
          <string-name>
            <surname>GRYGIEL</surname>
            ,
            <given-names>K.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>IDZIAK</surname>
            ,
            <given-names>P. M.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>AND ZAIONC</surname>
          </string-name>
          ,
          <string-name>
            <surname>M.</surname>
          </string-name>
          <year>2013</year>
          .
          <article-title>How big is BCI fragment of BCK logic</article-title>
          .
          <source>J. Log. Comput</source>
          .
          <volume>23</volume>
          ,
          <issue>3</issue>
          ,
          <fpage>673</fpage>
          -
          <lpage>691</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref10">
        <mixed-citation>
          <string-name>
            <surname>GRYGIEL</surname>
            ,
            <given-names>K.</given-names>
          </string-name>
          AND LESCANNE, P.
          <year>2013</year>
          .
          <article-title>Counting and generating lambda terms</article-title>
          .
          <source>J. Funct. Program. 23</source>
          ,
          <issue>5</issue>
          ,
          <fpage>594</fpage>
          -
          <lpage>628</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref11">
        <mixed-citation>
          <string-name>
            <surname>HINDLEY</surname>
            ,
            <given-names>J. R.</given-names>
          </string-name>
          AND SELDIN,
          <string-name>
            <surname>J. P.</surname>
          </string-name>
          <year>2008</year>
          .
          <article-title>Lambda-calculus and combinators: an introduction</article-title>
          . Vol.
          <volume>13</volume>
          . Cambridge University Press Cambridge.
        </mixed-citation>
      </ref>
      <ref id="ref12">
        <mixed-citation>
          <string-name>
            <surname>KAMAREDDINE</surname>
            ,
            <given-names>F.</given-names>
          </string-name>
          <year>2001</year>
          .
          <article-title>Reviewing the Classical and the de Bruijn Notation for calculus and Pure Type Systems</article-title>
          .
          <source>Journal of Logic and Computation</source>
          <volume>11</volume>
          ,
          <issue>3</issue>
          ,
          <fpage>363</fpage>
          -
          <lpage>394</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref13">
        <mixed-citation>
          <string-name>
            <surname>PALKA</surname>
            ,
            <given-names>M. H.</given-names>
          </string-name>
          , CLAESSEN,
          <string-name>
            <given-names>K.</given-names>
            ,
            <surname>RUSSO</surname>
          </string-name>
          ,
          <string-name>
            <surname>A.</surname>
          </string-name>
          ,
          <string-name>
            <surname>AND HUGHES</surname>
          </string-name>
          ,
          <string-name>
            <surname>J.</surname>
          </string-name>
          <year>2011</year>
          .
          <article-title>Testing an optimising compiler by generating random lambda terms</article-title>
          .
          <source>In Proceedings of the 6th International Workshop on Automation of Software Test. AST'11. ACM</source>
          , New York, NY, USA,
          <fpage>91</fpage>
          -
          <lpage>97</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref14">
        <mixed-citation>
          <string-name>
            <surname>SLOANE</surname>
            ,
            <given-names>N. J. A.</given-names>
          </string-name>
          <year>2014</year>
          .
          <article-title>The On-Line Encyclopedia of Integer Sequences</article-title>
          . Published electronically at https://oeis.org/.
        </mixed-citation>
      </ref>
      <ref id="ref15">
        <mixed-citation>
          <string-name>
            <surname>TARAU</surname>
            ,
            <given-names>P.</given-names>
          </string-name>
          2015a.
          <article-title>On a Uniform Representation of Combinators, Arithmetic, Lambda Terms and Types</article-title>
          .
          <source>In PPDP'15: Proceedings of the 17th international ACM SIGPLAN Symposium on Principles and Practice of Declarative Programming</source>
          , E. Albert, Ed. ACM, New York, NY, USA,
          <fpage>244</fpage>
          -
          <lpage>255</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref16">
        <mixed-citation>
          <string-name>
            <surname>TARAU</surname>
            ,
            <given-names>P.</given-names>
          </string-name>
          2015b.
          <article-title>On Logic Programming Representations of Lambda Terms: de Bruijn Indices, Compression, Type Inference, Combinatorial Generation, Normalization</article-title>
          .
          <source>In Proceedings of the Seventeenth International Symposium on Practical Aspects of Declarative Languages PADL'15</source>
          ,
          <string-name>
            <given-names>E.</given-names>
            <surname>Pontelli</surname>
          </string-name>
          and T. C. Son, Eds. Springer, LNCS
          <volume>8131</volume>
          ,
          <string-name>
            <surname>Portland</surname>
          </string-name>
          , Oregon, USA,
          <fpage>115</fpage>
          -
          <lpage>131</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref17">
        <mixed-citation>
          <source>THE UNIVALENT FOUNDATIONS PROGRAM</source>
          .
          <year>2013</year>
          .
          <article-title>Homotopy Type Theory</article-title>
          . Institute of Advanced Studies, Princeton. http://homotopytypetheory.org/
          <year>2013</year>
          /06/20/the-hott-book/.
        </mixed-citation>
      </ref>
    </ref-list>
  </back>
</article>