This paper introduces a type-checking algorithm for a complex type system supporting path polymorphism, combining recursive, union, and application types, with a focus on efficiency and correctness.
Contribution
It presents two algorithms for type equivalence and subtyping, including a polynomial-time automata-based method, improving the practicality of type checking for path polymorphism.
Coinductive characterizations underpin the type equivalence and subtyping algorithms.
03
Syntax-directed presentation proven equivalent to original system.
Abstract
A type system combining type application, constants as types, union types (associative, commutative and idempotent) and recursive types has recently been proposed for statically typing path polymorphism, the ability to define functions that can operate uniformly over recursively specified applicative data structures. A typical pattern such functions resort to is xy which decomposes a compound, in other words any applicative tree structure, into its parts. We study type-checking for this type system in two stages. First we propose algorithms for checking type equivalence and subtyping based on coinductive characterizations of those relations. We then formulate a syntax-directed presentation and prove its equivalence with the original one. This yields a type-checking algorithm which unfortunately has exponential time complexity in the worst case. A second algorithm is then proposed,…
\begin{array}[]{llll}\{\!\!\{{u}/{{x}}\}\!\!\}&\triangleq&\left\{{u}/{x}\right\}\\
\{\!\!\{{\mathtt{c}}/{\mathtt{c}}\}\!\!\}&\triangleq&\left\{{}\right\}\\
\{\!\!\{{{u}\,{v}}/{{p}\,{q}}\}\!\!\}&\triangleq&\{\!\!\{{u}/{p}\}\!\!\}\uplus\{\!\!\{{v}/{q}\}\!\!\}&\quad\text{if ${u}\,{v}$ is a \emph{matchable form}}\\
\{\!\!\{{u}/{p}\}\!\!\}&\triangleq&\mathtt{fail}&\quad\text{if $u$ is a \emph{matchable form}}\\
\{\!\!\{{u}/{p}\}\!\!\}&\triangleq&\mathtt{wait}\end{array}
\begin{array}[]{llll}\{\!\!\{{u}/{{x}}\}\!\!\}&\triangleq&\left\{{u}/{x}\right\}\\
\{\!\!\{{\mathtt{c}}/{\mathtt{c}}\}\!\!\}&\triangleq&\left\{{}\right\}\\
\{\!\!\{{{u}\,{v}}/{{p}\,{q}}\}\!\!\}&\triangleq&\{\!\!\{{u}/{p}\}\!\!\}\uplus\{\!\!\{{v}/{q}\}\!\!\}&\quad\text{if ${u}\,{v}$ is a \emph{matchable form}}\\
\{\!\!\{{u}/{p}\}\!\!\}&\triangleq&\mathtt{fail}&\quad\text{if $u$ is a \emph{matchable form}}\\
\{\!\!\{{u}/{p}\}\!\!\}&\triangleq&\mathtt{wait}\end{array}
\begin{array}[]{c}{tensy\vbox{\hbox spread0.0pt{\hskip 0.0pt plus 0.0001fil\hbox{$\displaystyle\penalty 1{\{\!\!\{{u}/{p_{i}}\}\!\!\}=\mathtt{fail}\text{ for all }i<j\quad\{\!\!\{{u}/{p_{j}}\}\!\!\}=\sigma_{j}\quad j\in 1..n}$}\hskip 0.0pt plus 0.0001fil}\hbox{\hbox{\kern 0.0pt\vrule height=0.25002pt,depth=0.25002pt,width=222.7092pt\hbox{\kern 3.00003pt${\textsc{({$\beta$})}}$}}}\hbox{\kern 72.04306pt\hbox{$\displaystyle{{({p_{i}}\shortrightarrow_{\theta_{i}}{s_{i}})_{i\in 1..n}}\,{u}\rightarrow\sigma_{j}s_{j}}$}}}}\end{array}
\begin{array}[]{c}{tensy\vbox{\hbox spread0.0pt{\hskip 0.0pt plus 0.0001fil\hbox{$\displaystyle\penalty 1{\{\!\!\{{u}/{p_{i}}\}\!\!\}=\mathtt{fail}\text{ for all }i<j\quad\{\!\!\{{u}/{p_{j}}\}\!\!\}=\sigma_{j}\quad j\in 1..n}$}\hskip 0.0pt plus 0.0001fil}\hbox{\hbox{\kern 0.0pt\vrule height=0.25002pt,depth=0.25002pt,width=222.7092pt\hbox{\kern 3.00003pt${\textsc{({$\beta$})}}$}}}\hbox{\kern 72.04306pt\hbox{$\displaystyle{{({p_{i}}\shortrightarrow_{\theta_{i}}{s_{i}})_{i\in 1..n}}\,{u}\rightarrow\sigma_{j}s_{j}}$}}}}\end{array}
No public reviews on file for this paper yet. If you reviewed it on a platform where reviews are public (OpenReview, ICLR, NeurIPS, ICML), you can paste yours below so the community can read it here.
Videos
No videos yet. Explain this paper in a talk, walkthrough, or lecture? Add one.
Full text
\Copyright
Juan Edi, Andrés Viso, and Eduardo Bonelli\serieslogo\volumeinfoTarmo Uustalu121st International Conference on Types for Proofs and
Programs (TYPES 2015)6911\EventShortNameTYPES 2015
\DOI10.4230/LIPIcs.xxx.yyy.p
Efficient Type Checking for Path Polymorphism
Juan Edi
Departamento de Computación
Facultad de Ciencias Exactas y Naturales
Universidad de Buenos Aires – UBA
Buenos Aires, Argentina
Andrés Viso
Consejo Nacional de Investigaciones Científicas y Técnicas – CONICET
Departamento de Computación
Facultad de Ciencias Exactas y Naturales
Universidad de Buenos Aires – UBA
Buenos Aires, Argentina
Eduardo Bonelli
Consejo Nacional de Investigaciones Científicas y Técnicas – CONICET
Departamento de Ciencia y Tecnología
Universidad Nacional de Quilmes – UNQ
Bernal, Argentina
Abstract.
A type system combining type application, constants as types, union types (associative,
commutative and idempotent) and recursive types has recently been proposed for statically typing
path polymorphism, the ability to define functions that can operate uniformly over
recursively specified applicative data structures. A typical pattern such functions resort to is
xy which decomposes a compound, in other words any applicative tree structure, into
its parts. We study type-checking for this type system in two stages. First we propose algorithms
for checking type equivalence and subtyping based on coinductive characterizations of those
relations. We then formulate a syntax-directed presentation and prove its equivalence with the
original one. This yields a type-checking algorithm which unfortunately has exponential time
complexity in the worst case. A second algorithm is then proposed, based on automata techniques,
which yields a polynomial-time type-checking algorithm.
Key words and phrases:
λ-Calculus, Pattern Matching, Path Polymorphism, Type Checking
1991 Mathematics Subject Classification:
F4.1 Lambda calculus and related systems,
F.3.2 Semantics of Programming Languages,
D.3.3 Language Constructs and Features.
1. Introduction
The lambda-calculus plays an important role in the study of
programming languages (PLs). Programs are represented as syntactic terms and
execution by repeated simplification of these terms using a reduction
rule called β-reduction. The study of the lambda-calculus
has produced deep results in both the theory and the implementation of
PLs. Many variants of the lambda-calculus have been introduced with
the purpose of studying specific PL features. One such feature of
interest is pattern-matching. Pattern-matching is used extensively in
PLs as a means for writing more succinct and, at the same time,
elegant programs. This is
particularly so in the functional programming community, but by no means
restricted to that community.
In the standard lambda-calculus,
functions are represented as expressions of the form λx.t, x
being the formal parameter and t the body. Such a function may be
applied to any term, regardless of its form. This is expressed
by the above mentioned β-reduction rule: (λx.t)s→β{s/x}t, where {s/x}t stands for the result of
replacing all free occurrences of x in t with s. Note that, in
this rule, no requirement on the form of s is placed.
Pattern calculi are generalizations of the β-reduction
rule in which
abstractions λx.t are replaced by λp.t where p is called a
pattern. An example is λ⟨x,y⟩.x for projecting the first
component of a pair, the pattern p being
⟨x,y⟩. An expression such as (λ⟨x,y⟩.x)s will only
be able to reduce if s indeed is of the form ⟨s1,s2⟩; it
will otherwise be blocked.
Patterns may be catalogued in at least two
dimensions. One is their structure and another their time of
creation. The structure of patterns may be very general.
Such is the case of variables: any term can match a variable, as
in the standard lambda-calculus. The structure of a pattern
may also be very specific. Such is the case when
arbitrary
terms are allowed to be
patterns [18, 14]. Regarding the
time of creation, patterns may either be static or
dynamic. Static patterns are those that are created at compile time,
such as the pattern ⟨x,y⟩ mentioned above. Dynamic patterns are those that may be generated at
run-time [12, 11]. For example,
consider the term λx.(λ(xy).y); note that it has an
occurrence of a pattern xy with a free variable, namely the x
in xy, that is bound to the outermost lambda. If this
term is applied to a constant c, then one obtains
λcy.y. However, if we apply it to the constant
d, then we obtain λdy.y. Both
patterns cy and dy
are created during execution. Note that one could also replace the x
in the pattern xy with an abstraction. This leads to computations
that evaluate to patterns.
Expressive pattern features may
easily break desired properties, such as confluence, and are not easy
to endow with type systems.
This work is an attempt at devising type systems for such expressive pattern
calculi. We originally set out to type-check the Pure Pattern Calculus
(PPC) [12, 11]. PPC is a
lambda-calculus that embodies the essence of dynamic patterns by
stripping away everything inessential to the reduction and matching
process of dynamic patterns. It admits terms such as λx.(λ(xy).y). We soon realized that
typing PPC was too challenging and noticed that the static fragment of
PPC, which we dub Calculus of Applicative Patterns (CAP), was
already challenging in itself. CAP also admits patterns such as
xy however all variables in this
pattern are considered bound. Thus, in a term such as
λ(xy).s both occurrences of x and y
are bound in s, disallowing reduction inside patterns. Such
patterns, however, allow arguments that are applications to be
decomposed, as long as these applications encode data
structures. They are therefore useful
for writing functions that operate on
semi-structured data.
The main obstacle for typing CAP is dealing
in the type system with a form of polymorphism called
path polymorphism [12, 11],
that arises from these kinds of patterns. We next briefly describe
path polymorphism and the requirements it
places on typing considerations.
Path Polymorphism. In CAP data structures are trees.
These trees are built using application
and variable arity constants or constructors. Examples of two such
trees follow, where the first one represents a list and the second
a binary tree:
[TABLE]
The constructor vl is used to tag values (1 and 2 in the first
case, and 3, 4 and 5 in the second). A “map” function for
updating the values of any of these two structures by applying some
user-supplied function f follows, where type annotations are omitted for
clarity:
[TABLE]
The expression upd(+1) may thus be applied to
any of the two data structures illustrated above. For example, we can evaluate
upd(+1)cons(vl1)(cons(vl2)nil)
and also
upd(+1)node(vl3)(node(vl4)nilnil)(node(vl5)nilnil). The expression to
the right of “=” is called an abstraction (or case) and
consists of a unique branch; this branch in turn is formed from a
pattern (f), and a body (in this case the body is itself another
abstraction that consists of three branches). An argument to an abstraction is
matched against the patterns, in the order in which they are written, and the
appropriate body is selected.
Notice the pattern xy. During evaluation
of upd(+1)cons(vl1)(cons(vl2)nil) the variables x and
y may be instantiated with different applicative terms in each
recursive call to upd. For example:
[TABLE]
The type assigned to x and y should encompass all
terms in its respective column.
Singleton Types and Type Application. A further
consideration in typing CAP is that terms such as the ones
depicted below should clearly not be typable.
[TABLE]
In the first case, cons
will never match nil. The type system will resort to
singleton types in order to determine this: cons will be
assigned a type of the form cons which will fail to match
nil. The second expression in (2)
breaks Subject Reduction (SR): reduction will produce
true+1. Applicative types of the form
vl@true will allow us to check
for these situations, @ being a new type constructor
that applies datatypes to arbitrary types. Also, note the use of
typing environments (the expression {x:Nature}) to declare the types of the variables of patterns
in branches. These are supplied by the programmer.
Union and Recursive Types. On the assumption that the programmer has provided an exhaustive
coverage, the type assigned by CAP to the variable x
in the pattern xy in upd is:
[TABLE]
Here μ is the recursive type constructor and ⊕ the
union type constructor. vl is the singleton type used for typing the constant
vl and @ denotes type application, as
mentioned above. The union type constructor is used to collect the
types of all the branches. The variable y in the pattern xy will
also be assigned the same type as x. Thus variables in applicative patterns are
assigned union types. upd itself is assigned type
(A⊃B)⊃(FA⊃FB), where FX is
μα.(vl@X)⊕(α@α)⊕(cons⊕node⊕nil).
Type-Checking for CAP. Based on these, and other
similar considerations, we proposed typed CAP [19], referred
to simply as CAP in the sequel. The system consists of typing rules that
combine singleton types, type application, union types, recursive types
and subtyping. Also it enjoys several properties, the salient one being
safety (subject reduction and progress). Safety relies on a notion of typed
pattern compatibility based on subtyping that guarantees that examples such as
(2–right) and the following one do not break safety:
[TABLE]
Assumptions on associativity and commutativity of typing
operators in [19], make it non-trivial
to deduce a type-checking algorithm from the typing rules.
The proposed type system is, moreover, not syntax-directed. Also, it relies
on coinductive notions of type equivalence and subtyping which in the presence
of recursive subtypes are not obviously decidable. A practical implementation
of CAP is instrumental since a robust theoretical analysis without such an
implementation is of little use.
Goal and Summary of Contributions.
This paper addresses this implementation. It
does so in two stages:
•
The first stage presents a naïve but correct, high-level description
of a type-checking algorithm, the principal aim being clarity. We propose an
invertible presentation of the coinductive notions of type-equivalence and
subtyping of [19] and also a syntax-directed variant of the
presentation in [19]. This leads to algorithms for checking
subtyping membership and equivalence modulo associative, commutative and
idempotent (ACI) unions, both based on an invertible presentation of the
functional generating the associated coinductive notions.
•
The second stage builds on ideas from the first algorithm with the aim
of improving efficiency. μ-types are interpreted as infinite n-ary
trees and represented using automata, avoiding having to explicitly handle
unfoldings of recursive types, and leading to a significant improvement in
the complexity of the key steps of the type-checking process, namely equality
and subtype checking.
**Related work. **
For literature on (typed) pattern calculi the reader is referred
to [19]. The algorithms for checking equality of recursive
types or subtyping of recursive types have been studied in the 1990s by
Amadio and Cardelli [1]; Kozen, Palsberg, and
Schwartzbach [15]; Brandt and Henglein [4]; Jim and
Palsberg [13] among others.
Additionally, Zhao and Palsberg [16] studied
the possibilities of incorporating associative and commutative (AC) products to
the equality check, on an automata-based approach that the authors themselves
claimed was not extensible to subtyping [21]. Later on Di Cosmo,
Pottier, and Rémy [7] presented another
automata-based algorithm for subtyping that properly handles AC products with a
complexity cost of O(n2n′2d5/2), where n and n′ are the sizes of
the analyzed types, and d is a bound on the arity of the involved products.
Structure of the paper. Sec. 2 reviews the syntax
and operational semantics of CAP, its type system and the main properties.
Further details may be consulted in [19].
Sec. 3 proposes invertible generating functions for
coinductive notions of type-equivalence and subtyping that lead to inefficient
but elegant algorithms for checking these relations.
Sec. 4 proposes a syntax-directed type system for CAP.
Sec. 5 studies a more efficient type-checking
algorithm based on automaton. Finally, we conclude in
Sec. 6. An implementation of the algorithms
described here is available online [10].
2. Review of CAP
2.1. Syntax and Operational Semantics
We assume given an infinite set of term variables V and constants
C. CAP has four syntactic categories, namely patterns
(p,q,…), terms (s,t,…), data structures
(d,e,…) and matchable forms (m,n,…):
[TABLE]
The set of patterns, terms, data structures and matchable forms are denoted
P, T, D and M, resp. Variables
occurring in patterns are called matchables. We often abbreviate
p1\shortrightarrowθ1s1∣…∣pn\shortrightarrowθnsn
with (pi\shortrightarrowθisi)i∈1..n. The θi are typing
contexts annotating the type assignments for the variables in pi (*cf. *Sec. 2.3). The free variables of a term t
(notation fv(t)) are defined as expected; in a pattern p we call them
free matchables (fm(p)). All free matchables in each pi are
assumed to be bound in their respective bodies si. Positions in patterns and
terms are defined as expected and denoted π,π′,… (ϵ denotes
the root position). We write pos(s) for the set of positions of s and
\andsπ for the subterm of s occurring at position π.
A substitution (σ,σi,…) is a partial function
from term variables to terms. If it assigns ui to xi, i∈1..n, then
we write {u1/x1,…,un/xn}. Its domain (dom(σ)) is
{x1,…,xn}. Also, {} is the identity substitution. We write
σs for the result of applying σ to term s. We say a pattern
psubsumes a pattern q, written p⊲q if there exists
σ such that σp=q. Matchable forms are required for
defining the matching operation, described next.
Given a pattern p and a term s, the matching operation {{s/p}}
determines whether s matches p. It may have one of three outcomes: success,
fail (in which case it returns the special symbol fail) or undetermined (in
which case it returns the special symbol wait). We say {{s/p}}
is decided if it is either successful or it fails. In the former it
yields a substitution σ; in this case we write {{s/p}}=σ. The disjoint union of matching outcomes is given as follows
(“≜” is used for definitional equality):
[TABLE]
where o denotes any possible output and σ1⊎σ2≜σ if the domains of σ1 and σ2 are disjoint. This always
holds given that patterns are assumed to be linear (at most one occurrence of
any matchable). The matching operation is defined as follows, where the
defining clauses below are evaluated from top to bottom111This is
simplification to the static patterns case of the matching operation introduced
in [12].:
[TABLE]
For example: {{x\shortrightarrows/c}}=fail; {{d/c}}=fail;
{{x/c}}=wait and
{{xd/cc}}=fail. We now turn to the only reduction axiom of CAP:
[TABLE]
It may be applied under any context and states that if the argument u to an
abstraction (pi\shortrightarrowθisi)i∈1..n fails to match all
patterns pi with i<j and successfully matches pattern pj (producing a
substitution σj), then the term
(pi\shortrightarrowθisi)i∈1..nu reduces to
σjsj.
For instance, consider the function
[TABLE]
Then, headnil→nothing
with {{nil/nil}}={}, while
head(cons4nil)→just4
since {{consxnil/nil}}=fail and {{cons4nil/consxxs}}={4/x,nil/xs}.
In order to ensure that patterns such as
xy decompose only data structures rather
than arbitrary terms, we shall introduce two sorts of typing expressions:
types and datatypes, the latter being strictly included in the
former. We assume given countably infinite sets VD of
datatype variables (α,β,…), VA of
type variables(X,Y,…) and C of type
constants(c,d,…). We define V≜VA∪VD and use meta-variables V,W,… to denote an arbitrary element in it. Likewise, we write a,b,…
for elements in V∪C. The sets TD of
μ-datatypes and T of μ-types, resp., are
inductively defined as follows:
[TABLE]
Remark 2.1**.**
A type of the form μα.A is not valid in general since it may
produce invalid unfoldings. For example,
μα.α⊃α=(μα.α⊃α)⊃(μα.α⊃α),
which fails to preserve sorting.
On the other hand, types of the form μX.D are not necessary since
they denote the solution to the equation X=D, hence X is a
variable representing a datatype, a role already fulfilled by α.
We consider ⊕ to bind tighter than ⊃, while @
binds tighter than ⊕. E.g. D@A⊕A′⊃B means
((D@A)⊕A′)⊃B. We write A=⊕
to mean that the root symbol of A is different from ⊕; and similarly
with the other type constructors.
Expressions such as A1⊕…⊕An will be
abbreviated ⊕i∈1..nAi; this is sound since μ-types
will be considered modulo associativity of ⊕. A type of the form
⊕i∈1..nAi where each Ai=⊕, i∈1..n, is called a maximal union. We often write μV.A to
mean either μα.D or μX.A. A non-union
μ-typeA is a μ-type of one of the following forms: α,
c, D@A′, X, A′⊃A′′ or μV.B
with B a non-union μ-type. We assume μ-types are
contractive: μV.A is contractive if V occurs in A
only under a type constructor ⊃ or @, if at all.
For
instance, μX.X⊃c, μX.X⊃X and
μX.c@X⊕X are contractive
while μX.X and μX.X⊕X are not. We
henceforth redefine T to be the set of contractive μ-types.
μ-types come equipped with a notion of type equivalence≃μ (Fig. 1) and subtyping⪯μ (Fig. 2). In
Fig. 2 a subtyping context Σ is a set of
assumptions over type variables of the form V⪯μW with V,W∈V. (e-rec) actually encodes two rules, one for datatypes
(μα.D) and one for arbitrary types (μX.A).
Likewise for (e-fold) and (e-contr).
Regarding the subtyping rules, we adopt those for union
of [20]. It should be noted that the naïve variant
of (s-rec) in which Σ⊢μV.A⪯μμV.B is deduced from Σ⊢A⪯μB, is known to be
unsound [1]. We often abbreviate ⊢A⪯μB as A⪯μB.
2.3. Typing and Safety
A typing contextΓ (or θ) is a partial function from
term variables to μ-types; Γ(x)=A means that Γ maps x to
A. We have two typing judgments, one for patterns θ⊢pp:A
and one for terms Γ⊢s:A. Accordingly, we have two sets of
typing rules: Fig. 3, top and bottom.
We write ⊳θ⊢pp:A to indicate that the typing judgment
θ⊢pp:A is derivable (likewise for ⊳Γ⊢ps:A).
The typing schemes speak for themselves except for two of them which we now
comment. The first is (t-app). Note that we do not impose any additional
restrictions on Ai, in particular it may be a union-type itself. This implies
that the argument u can have a union type too.
Regarding (t-abs) it requests a number of conditions. First of all, each of
the patterns pi must be typable under the typing context θi, i∈1..n. Also, the set of free matchables in each pi must be exactly the
domain of θi. Another condition, indicated by (Γ,θi⊢si:B)i∈1..n, is that the bodies of each of the branches
si, i∈1..n, must be typable under the context extended with the
corresponding θi. More noteworthy is the condition that the list
[pi:Ai]i∈1..n be compatible.
Compatibility is a condition that ensures that Subject Reduction is not violated. We briefly
recall it; see [19] for further details and examples. As already
mentioned in example (3) of the introduction, if
pi subsumes pj (i.e. pi⊲pj) with i<j, then the branch pj\shortrightarrowθjsj
will never be evaluated since the argument will already match pi. Thus, in
this case, in order to ensure SR we demand that Aj⪯μAi. If pi
does not subsume pj (i.e. pi\centernot⊲pj) with i<j we analyze the
cause of failure of subsumption in order to determine whether requirements on
Ai and Aj must be put forward, focusing on those cases where π∈pos(pi)∩pos(pj) is an offending position in both patterns. The
following table exhaustively lists them:
[TABLE]
In cases (b), (c) and (e), no extra condition on the types of pi and
pj is necessary, since their respective sets of possible arguments are
disjoint. The cases where Ai and Aj must be related are (a) and (d): for
those we require Aj⪯μAi. In summary, the cases requiring
conditions on their types are: 1) pi⊲pj; and 2)
pi\centernot⊲pj and pj⊲pi.
Definition 2.2**.**
Given a pattern θ⊢pp:A and π∈pos(p), we say Aadmits a symbol ⊙ (with ⊙∈V∪C∪{⊃,@})at positionπ iff ⊙∈A∥π, where:
[TABLE]
Note that ⊳θ⊢pp:A and contractiveness of A imply
A∥π is well-defined for π∈pos(p).
Definition 2.3**.**
The maximal positions in a set of positions P are:
[TABLE]
The mismatching positions between two patterns are defined
below where, recall from the introduction, \andpπ stands for the sub-pattern
at position π of p:
[TABLE]
For instance, given patterns nil and
consxxs with set of positions
{ϵ} and {ϵ,1,2,11,12} respectively, we have
maxpos(nil)={ϵ} and
maxpos(consxxs)={11,12},
while the only mismatching position among them is the root, i.e. mmpos(nil,consxxs)={ϵ}.
Definition 2.4**.**
Define the compatibility predicate as
[TABLE]
We say p:A is compatible with q:B, notation p:A⋘q:B, iff
[TABLE]
A list of patterns [pi:Ai]i∈1..n is
compatible if ∀i,j∈1..n.i<j⟹pi:Ai⋘pj:Aj.
Following the example above, consider types nil and
cons@Nature@(μα.nil⊕cons@Nature@α)
for patterns nil and consxxs
respectively. Compatibility requires no further restriction in this case since
mmpos(nil,consxxs)={ϵ}
and
[TABLE]
hence Pcomp is false and the property gets validated trivially.
On the contrary, recall motivating example (3) on Sec. 1.
vlx:vl@Bool⋘vly:vl@Nature requires vl@Nature⪯μvl@Bool since
mmpos(vlx,vly)=∅ (i.e. Pcomp is trivially true). This actually fails because Nature⪯μBool. Thus, this pattern combination is rejected by rule (t-abs).
Types are preserved along reduction. The proof relies crucially on compatibility.
Proposition 2.5** (Subject Reduction).**
If ⊳Γ⊢ps:A and s→s′, then
⊳Γ⊢ps′:A.
Let the set of values be defined as v::=xv1…vn∣cv1…vn∣(pi\shortrightarrowθisi)i∈1..n. The following property guarantees
that no functional application gets stuck. Essentially this means that, in a
well-typed closed term, a function which is applied to an argument has at least
one branch that is capable of handling it.
Proposition 2.6** (Progress).**
If ⊳⊢ps:A and s is not a value, then ∃s′ such that s→s′.
3. Checking Equivalence and Subtyping
As mentioned in the related work, there are roughly two approaches to
implementing equivalence and subtype checking in the presence of recursive
types, one based on automata theory and another based on coinductive
characterizations of the associated relations. The former leads to efficient
algorithms [16] while the latter is more
abstract in nature and hence closer to the formalism itself although they may
not be as efficient. In the particular case of subtyping for recursive types in
the presence of ACI operators, the automata approach of [16] is known
not to be applicable [21] while the coinductive approach,
developed in this section, yields a correct algorithm. In
Sec. 5 we explore an alternative approach for
subtyping based on automata inspired
from [7]. We next further describe the
reasoning behind the coinductive approach.
3.1. Preliminaries
Consider type constructors@ and ⊃ together
with type connector⊕ and the ranked alphabet
L≜{a0∣a∈V∪C}∪{@2,⊃2,⊕2}. We write T for the
set of (possibly) infinite types with symbols in L.
This is a standard construction [3, 8] given
by the metric completion based on a simple depth function measuring the
distance from the root to the minimum conflicting node in two trees.
Perhaps worth mentioning is that the type connector ⊕ does not
contribute to the depth (hence the reason for calling it a connector rather
than a constructor) excluding types consisting of infinite branches of
⊕, such as
(…⊕…)⊕(…⊕…), from
T. A tree is regular if the set of all its subtrees is finite.
We shall always work with regular trees and also denote them T.
Definition 3.1**.**
The truncation of a tree A at depth k∈N (notation
A∣k) is defined inductively222This definition is
well-founded [19]. as follows:
[TABLE]
where ∘∈C is a distinguished type
constant used to identify the nodes where the tree was truncated.
Definition 3.2**.**
The function [[∙]]T:T→T, mapping μ-types to
types, is defined inductively as follows:
[TABLE]
Coinductive characterizations of subsets of T×T whose generating
function Φ is invertible admit a simple (although not necessarily
efficient) algorithm for subtype membership checking and consists in “running
Φ backwards” [17, Sec. 21.5]. This strategy is
supported by the fact that contractiveness of μ-types guarantees a finite
state space to explore (*i.e. *unfolding these types results in regular trees);
invertibility further guarantees that there is at most one way in which a
member of νΦ, the greatest fixed-point of Φ, can be generated.
Invertibility of Φ:℘(T×T)→℘(T×T) means that for any ⟨A,B⟩∈T, the set
{X∈℘(T×T)∣⟨A,B⟩∈Φ(X)}
is either empty or contains a unique member.
3.2. Equivalence Checking
Fig. 4 presents a coinductive definition of
type equality over μ-types. This relation ≃μ is defined
by means of rules that are interpreted coinductively
(indicated by the double lines). The rule (e-union-al) makes use
of functions f and g to encode the ACI nature of ⊕. Letters C,D,
used in rules (e-rec-l-al) and (e-rec-r-al), denote contexts of the form:
[TABLE]
where □ denotes the hole of the context, Aj=⊕ for all j∈1..n∖i and Al=μ for
all l∈1..i−1. Note that, in particular, C may take the form
□. These contexts help identify the first occurrence of a μ
constructor within a maximal union. In turn, this allows us to guarantee the invertibility of the
generating function associated to these rules.
Proposition 3.3**.**
The generating function associated with the rules of Fig. 4 is invertible.
Moreover, ≃μ coincides with ≃μ:
Proposition 3.4**.**
A≃μB* iff A≃μB.*
This will allow us to check A≃μB by using the invertibility of the
generating function (implicit in the rules of Fig. 4)
for ≃μ. The proof of Prop. 3.4
relies on an intermediate relation ≃T over the possibly infinite trees
resulting from the complete unfolding of μ-types. This relation is defined
using the same rules as in Fig. 4 except for two
important differences: 1) the relation is defined over regular trees in T,
and 2) rules (e-rec-l-al) and (e-rec-r-al) are dropped.
The proof is structured as follows. First we characterize equality of
μ-types in terms of equality of their infinite unfoldings [19]:
Proposition 3.5**.**
A≃μB* iff [[A]]T≃T[[B]]T.*
The proof of Prop. 3.4 thus reduces to
showing that A≃μB coincides with [[A]]T≃T[[B]]T. In order to do so, we appeal to the following result that states
that inspecting all finite truncations suffices to determine whether
[[A]]T≃T[[B]]T holds:
Lemma 3.6**.**
∀k∈N.A∣k≃TB∣k* iff A≃TB.*
Proof 3.7**.**
This is proved by showing that the relations S≜{⟨A,B⟩∣∀k∈N.A∣k≃TB∣k} and
R≜{⟨A∣k,B∣k⟩∣A≃TB,k∈N} are Φ≃T-dense. Then we conclude by the coinductive
principle. For full details refer to [19].
The proofs of Lem. 3.13
and 3.20 rely on some key lemmas which
we now state, preceded by some preliminary notions. Let A,B,… refer
to (multi-hole) μ⊕-contexts:
[TABLE]
When A consists solely of μ type constructors, then we say that
it is a μ-context. As for types, we use notation ⊕i∈1..nAi when referring to a context irrespective of how unions are
associated within it. Any A∈T, can be uniquely written as a
maximal μ⊕-contextA=A[A1,…,An],
where each Ai=μ,⊕, i∈1..n. The
μ⊕-depth of A is the depth of A.
Definition 3.8**.**
The projection of a hole’s position π in A, notation
A[A]π, is defined by induction on A as follows:
[TABLE]
We write A∖μ for the μ⊕-context resulting from
dropping all the μ type constructors from A:
[TABLE]
Lemma 3.9**.**
Let A be a μ⊕-context. Then,
[TABLE]
where πi is the position of the
i-th hole (in the left-to-right order) in A.
Proof 3.10**.**
Induction on the context A.
•
A=□:
[TABLE]
•
A=μV.A′:
[TABLE]
•
A=A1⊕A2:
[TABLE]
where [π1,…,πn]=[1π1′,…,1πn1′,2π1′′,…,2πn2′′].
We also need to deduce the form of a type A whose associated tree is a
maximal union type.
Lemma 3.11**.**
Let A∈T, Ai∈T for i∈1..n such that [[A]]T=⊕i∈1..nAi and Ai=⊕. Then, there
exists n′≤n, A,A1,…,An′ maximal
⊕-contexts, A1,…,An′=⊕ and functions
s,t:1..n′→1..n such that
[TABLE]
for every l∈1..n′.
Proof 3.12**.**
As noted before, every A∈T can be uniquely written as a maximal
μ⊕-context A′ and types A1′,…,Am′ such that
Aj′=μ,⊕ for all j∈1..m, i.e. A=A′[A′]. It is immediate to see, by Def. 3.2
and 3.8, that m=n and
[TABLE]
for every i∈1..n.
Then, we can decompose A′ into two parts, namely a maximal
⊕-context A with n′≤n holes, and multiple
μ⊕-contexts A1′,…,An′′ such that A′=A[A′] and each Al′ is either □ or starts with μ
for every l∈1..n′. Thus, there exists types A1,…,An′ and
functions s,t:1..n′→1..n such that
[TABLE]
Note that Al=⊕ since Al′=□,μ for every
l∈1..n′.
Finally, let ρ1,…,ρnl be the positions of the holes in
Al′, we have
[TABLE]
for every l∈1..n′. Then, it is enough to take Al=Al′∖μ.
Finally, we show that A≃μB can be determined by checking all finite
truncations of its associated regular trees:
Lemma 3.13**.**
A≃μB* iff ∀k∈N.[[A]]T∣k≃T[[B]]T∣k.*
Proof 3.14**.**
For this proof we use notation #μ(A) for the number of
occurrences of the μ type constructor in the maximal
μ⊕-context A defining A=A[A].
⇒)* Given A≃μB, there exists S∈℘(T×T) such that S⊆Φ≃μ(S) and
⟨A,B⟩∈S. Define:*
[TABLE]
We show that R(S)⊆Φ≃T(R(S)).
Define Sc≜{⟨A′,B′⟩∈S∣c=#μ(A)+#μ(B)}. For each c∈N, we prove:
[TABLE]
Note that if k=0, the result follows directly from (e-refl-t) since
⟨[[A′]]T∣k,[[B′]]T∣k⟩=⟨∘,∘⟩∈Φ≃T(R(S)) trivially. So we in fact prove
[TABLE]
We proceed by induction on c.
•
c=0. Since ⟨A,B⟩∈S0 implies ⟨A,B⟩∈S⊆Φ≃μ(S), one of the following cases must hold:
–
⟨A,B⟩=⟨a,a⟩. Then
⟨[[A]]T∣k,[[A]]T∣k⟩=⟨a,a⟩ for every
k>0 and we conclude by (e-refl-t), Φ≃T(R(S)).
–
⟨A,B⟩=⟨A′⊃B′,A′′⊃B′′⟩* with
⟨A′,A′′⟩∈S and ⟨B′,B′′⟩∈S. Then, by definition of
R we have both
⟨[[A′]]T∣k−1,[[A′′]]T∣k−1⟩,⟨[[B′]]T∣k−1,[[B′′]]T∣k−1⟩∈R(S) for
every k>0. Finally, by (e-func-t) and Def. 3.1,*
[TABLE]
for every k>0.
–
⟨A,B⟩=⟨D@A′,D′@B′⟩* with
⟨D,D′⟩∈S and ⟨A′,B′⟩∈S. Similarly to the previous
case, we get ⟨[[D]]T∣k−1,[[D′]]T∣k−1⟩,⟨[[A′]]T∣k−1,[[B′]]T∣k−1⟩∈R(S) for any
k>0 from Def. 3.2, and conclude by applying
(e-comp-t) with Def. 3.1.*
–
⟨A,B⟩=⟨⊕i∈1..nAi,⊕j∈1..mBj⟩* with n+m>2, Ai,Bj=μ,⊕ and
there exists functions f:1..n→1..m,g:1..m→1..n s.t.
⟨Ai,Bf(i)⟩∈S and ⟨Ag(j),Bj⟩∈S for every
i∈1..n,j∈1..m.*
Once again, we have
⟨[[Ai]]T∣k,[[Bf(i)]]T∣k⟩,⟨[[Ag(j)]]T∣k,[[Bj]]T∣k⟩∈R(S) for
every i∈1..n,j∈1..m,k>0 by Def. 3.2 and R.
Moreover, since Ai,Bj=μ,⊕ we can assure
[[Ai]]T,[[Bj]]T=⊕ too. Thus, we are able to
apply (e-union-t) with f and g to conclude,
[TABLE]
for every k>0.
•
c>1. Then:
–
⟨A,B⟩=⟨C[μV.A′],B⟩* with
⟨C[{μV.A′/V}A′],B⟩∈S. By
contractiveness of μ-types, we have
#μ(C[{μV.A′/V}A′])<#μ(C[μV.A′]). Hence we can apply the
inductive hypothesis to get*
[TABLE]
for every k>0. Moreover, since
[[C[μV.A′]]]T=[[C[{μV.A′/V}A′]]]T by
Def. 3.2, we can safely conclude.
–
⟨A,B⟩=⟨A,D[μW.B′]⟩* with
⟨A,D[{μW.B′/W}B′]⟩∈S and A=C[μV.C]. As before, we conclude directly from the
inductive hypothesis by resorting to contractiveness of μ-types. Thus,*
[TABLE]
for every k>0.
⇐)* We show that R≜{⟨A′,B′⟩∣A′,B′∈T,∀k∈N.[[A′]]T∣k≃T[[B′]]T∣k} is Φ≃μ-dense.*
Let ⟨A,B⟩∈R. We proceed by induction on c=#μ(A)+#μ(B). From now on we consider k>0 to avoid the border case
⟨[[A]]T∣0,[[B]]T∣0⟩=⟨∘,∘⟩.
•
c=0. Since ⟨[[A]]T∣k,[[B]]T∣k⟩∈≃T and ≃T=Φ≃T(≃T), one
of the following cases must hold:
–
⟨[[A]]T∣k,[[B]]T∣k⟩=⟨a,a⟩.
Then, since c=0 it must be the case A=a=B. Thus, by
(e-refl-al), ⟨A,B⟩∈Φ≃μ(R).
Once again, since the outermost constructor of both A and B is not
μ, there exists A′,A′′,B′,B′′∈T such that A=A′⊃A′′ and B=B′⊃B′′ with [[A′]]T=A′,
[[A′′]]T=A′′, [[B′]]T=B′ and [[B′′]]T=B′′.
Moreover, from (6) and the definition of R we get
⟨A′,B′⟩,⟨A′′,B′′⟩∈R. We conclude with (e-func-al),
⟨A,B⟩∈Φ≃μ(R).
As in the previous case, we
know there exists D,D′,A′,B′∈T such that A=D@A′,
B=D′@B′ and ⟨D,D′⟩,⟨A′,B′⟩∈R. Here we
use (e-comp-al) to conclude.
–
⟨[[A]]T∣k,[[B]]T∣k⟩=⟨⊕i∈1..nAi∣k,⊕j∈1..mBj∣k⟩*
with n+m>2, Ai∣k,Bj∣k=⊕ and there
exists functions f:1..n→1..m,g:1..m→1..n such that*
[TABLE]
for every i∈1..n,j∈1..m.
By Lem. 3.11 on A, there exists n′≤n,
maximal ⊕-contexts A,A1,…,An′, types A1,…,An′=⊕ and functions s,t:1..n′→1..n such
that
[TABLE]
for every l∈1..n′. Moreover,
since #μ(A)=0 and A is maximal, it can only be the
case that n′=n and Al=□ for every l∈1..n′. Thus, s=t=id and
[TABLE]
for every i∈1..n.
With a similar analysis we have B=B[B] with B a maximal
⊕-context, and
[TABLE]
for every j∈1..m. Then, from (7),
(8)-left and (9)-left we get
[TABLE]
for every i∈1..n,j∈1..m. Finally, we
apply (e-union-al) with f, g, (8)-right and
(9)-right to conclude
⟨⊕i∈1..nAi,⊕j∈1..mBj⟩∈Φ≃μ(R).
•
c>0. Then we need to distinguish two cases:
–
#μ(A)=0. Then, it is necessarily the case
#μ(B)>0. Thus, B=D[μW.B′] and, by
Def. 3.2, we have
[TABLE]
for
every k∈N. Moreover, by contractiveness of μ-types we
know that
[TABLE]
and we can apply the
inductive hypothesis to get
⟨A,D[{μW.B′/W}B′]⟩∈R.
Note that #μ(A)=0 implies A=C[μV.A′]. Then, we are under the hypothesis of rule
(e-rec-r-al), and we conclude ⟨A,D[μW.B′]⟩∈Φ≃μ(R).
–
#μ(A)>0. Then, A=C[μV.A′].
Similarly to the previous case, by Def. 3.2 we have
[TABLE]
for
every k∈N. By contractiveness of μ-types we can safely
apply the inductive hypothesis to get
⟨C[{μV.A′/V}A′],B⟩∈R, and
finally conclude with rule (e-rec-l-al),
⟨C[μV.A′],B⟩∈Φ≃μ(R).
Thus we can resort to invertibility of the generating function to check for
≃μ. Fig. 5 presents the algorithm. It
uses seqe1…en which sequentially evaluates each of its
arguments, returning the value of the first of these that does not
fail. Evaluation of eqtype(∅,A,B) can have one of two
outcomes: fail, meaning that A≃μB, or a set S∈℘(T×T) that is Φ-dense with (A,B)∈S,
proving that A≃μB.
3.3. Subtype Checking
The approach to subtype checking is similar to that of type equivalence.
First consider the relation ⪯μ over μ-types defined in
Fig. 6. It captures ⪯μ:
Proposition 3.15**.**
A⪯μB* iff A⪯μB.*
The proof strategy is similar to that of
Prop. 3.4. In this case we resort to a
proper subtyping relation for infinite trees that essentially results from
dropping rules (s-rec-l-al) and (s-rec-r-al) in
Fig. 6.
In this case we resort to Prop. 3.16 and
Lem. 3.17 to establish a relation with ⪯μ via
the infinite trees semantics and its finite truncations [19].
Proposition 3.16**.**
A⪯μB* iff [[A]]T⪯T[[B]]T.*
Lemma 3.17**.**
∀k∈N.A∣k⪯TB∣k* iff A⪯TB.*
The following lemma allows us to relate the different non-union projections of
two maximal union types that belong to a Φ⪯μ-dense relation.
Lemma 3.18**.**
Let A,B∈T. Suppose ⟨A,B⟩∈S and S⊆Φ⪯μ(S). Let A be the maximal μ⊕-context
such that A=A[A1,…,An], for some Ai, i∈1..n, and B
the maximal μ⊕-context such that B=B[B1,…,Bm]. Then, there exists f:1..n→1..m such that for each i∈1..n,
⟨A[A]πi,B[B]ρf(i)⟩∈S.
Proof 3.19**.**
Induction on the sum of the μ⊕-depths.
•
If the sum is 0, then A=□=B and the result is immediate.
•
If it is greater than 0, we analyze the shape of A:
–
A=□. Then n=1 and An=A=μ,⊕
and we have two possibilities for B:
(1)
B=μW.B′. Then the only rule that applies is
(s-rec-r-al). By hypothesis of the rule,
⟨A,{μW.B′[B]/W}B′[B]⟩∈S. Moreover, since
[TABLE]
and
μ-types are contractive (hence none of the B can be
variables), we can assure B′ is a maximal
μ⊕-context too. Then, by inductive hypothesis, there
exists f:1..n→1..m such that
[TABLE]
for each i∈1..n. Finally, we conclude by
Def. 3.8,
⟨A[A]πi,(μW.B′[B])1ρf(i)⟩∈S.
2. (2)
B=B1⊕B2. From B=B[B], with a
similar analysis to the one made for the proof of
Lem. 3.11, we can decompose B into a maximal
⊕-context B′ and multiple μ⊕-contexts
B1′,…,Bm′′ with m′≤m. Then, there exists types
B1′,…,Bm′′ and functions s,t:1..m′→1..m such that
[TABLE]
for every l∈1..m′. Moreover, since B=B1⊕B2
and B′ is maximal, we have m′>1 and Bl′=⊕ for
every l∈1..m′.
*Then, we can assure that the only rule that applies for ⟨A,B⟩∈S is (s-union-r-al). By hypothesis of it, ⟨A,Bk′⟩∈S
for some k∈1..m′. Let mk=t(k)−s(k) (*i.e. the number of holes in
Bk′). By inductive hypothesis and
(10)-right with l=k, there exists f:1..n→1..mk such that
[TABLE]
where τhk is the position of the (h−s(k))-th hole in
Bk′. Let ρk′ be the position of the k-th hole in B′ and
take ρh=ρk′τhk. Then, by Def. 3.8
[TABLE]
Finally, since B′[B′]=B=B[B], we resort to the hypothesis and
(10)-left to conclude
⟨A[A]πi,B[B]ρf(i)⟩∈S.
–
A=μV.A′. Then the only rule that applies is
(s-rec-l-al) and we have
[TABLE]
As before, by contractiveness of μ-types, we get
⟨A′[{μV.A′[A]/V}A],B[B]⟩∈S with A′ still a maximal μ⊕-context. Then, by
inductive hypothesis, there exists f:1..n→1..m such that
[TABLE]
for each i∈1..n. Once again we conclude by
Def. 3.8,
⟨(μV.A′[A])1πi,B[B]ρf(i)⟩∈S.
–
A=A1⊕A2. Here we have two possibilities for
B:
(1)
B=μ* (i.e. B=μW.B′). Then, it can only
be the case of (s-rec-r-al) and analysis here is analogous to the one
presented before.*
2. (2)
B=μ. This case is similar to the one for B=B1⊕B2 presented above. Here we have A=A[A] and we can decompose A into a maximal
⊕-context A′ and multiple μ⊕-contexts
A1′,…,An′′ with n′≤n. Then, there exists types
A1′,…,An′′ and functions s,t:1..n′→1..n such that
[TABLE]
*for every l∈1..n′. Again we get Al′=⊕ and n′>1, thus we can only apply (s-union-l-al) for ⟨A,B⟩∈S.
By hypothesis of the rule we know ⟨Al′,B⟩∈S for every l∈1..n′. Now we take nl=t(l)−s(l) (*i.e. the number of holes in
Al′) and we apply the inductive hypothesis on each assumption of
the rule. Thus, there exists fl:1..nl→1..m such that
[TABLE]
for every l∈1..n′. Then, let πl′ be the position of
the l-th hole in A′ and πi=πl′τil to get
[TABLE]
Finally, we combine all functions fl
into one f:1..n→1..m, and resort to
(11)-left (i.e. A′[A′]=A=A[A]) to conclude with
⟨A[A]πi,B[B]ρf(i)⟩∈S.
Finally, we prove:
Lemma 3.20**.**
A⪯μB* iff ∀k∈N.[[A]]T∣k⪯T[[B]]T∣k.*
Proof 3.21**.**
In the following proof we denote with #μ(A) the number
μ type constructors at the head of type A:
[TABLE]
⇒)* Given A⪯μB, there exists S∈℘(T×T) such that S⊆Φ⪯μ(S) and
⟨A,B⟩∈S. Define:*
[TABLE]
We show that R(S)⊆Φ⪯T(R(S)).
Define Sc≜{⟨A′,B′⟩∈S∣c=#μ(A′)+#μ(B′)}. For each c∈N, we
prove:
[TABLE]
Note that if k=0, the result follows directly from (s-refl-t) since
⟨[[A′]]T∣k,[[B′]]T∣k⟩=⟨∘,∘⟩∈Φ⪯T(R(S)) trivially. So we in fact prove
[TABLE]
We proceed by induction on c.
•
c=0. Since ⟨A,B⟩∈S and S is Φ⪯μ-dense
one of the following cases must occur:
–
⟨A,B⟩=⟨a,a⟩. Then for any k>0,
⟨[[A]]T∣k,[[B]]T∣k⟩=⟨a,a⟩∈Φ⪯T(R(S)) by (s-refl-t).
–
⟨A,B⟩=⟨A′⊃B′,A′′⊃B′′⟩* and
⟨A′′,A′⟩∈S and ⟨B′,B′′⟩∈S. From ⟨A′′,A′⟩∈S we have ⟨[[A′′]]T∣k−1,[[A′]]T∣k−1⟩∈R(S), for any k>0, as follows from Def. 3.2.
Similarly,
⟨[[B′]]T∣k−1,[[B′′]]T∣k−1⟩∈R(S). Then
by (s-func-t) and Def. 3.1,*
[TABLE]
for any k>0.
–
⟨A,B⟩=⟨D@A′,D′@B′⟩* and
⟨D,D′⟩∈S and ⟨A′,B′⟩∈S. As before, we get
⟨[[D]]T∣k−1,[[D′]]T∣k−1⟩,⟨[[A′]]T∣k−1,[[B′]]T∣k−1⟩∈R(S) for any
k>0 from the definition of T, and conclude by applying
(s-comp-t) with Def. 3.1.*
–
⟨A,B⟩=⟨⊕i∈1..nAi,B⟩* with n>1, B=μ, Ai=⊕ and ⟨Ai,B⟩∈S
for all i∈1..n. A can alternately be written as A[A]
where A is a maximal ⊕-context.*
Let A′ be the μ⊕-context such that A=A′[A′] with Ai′=μ,⊕ for all i∈1..n′ (note that n′≥n). Similarly, let B the
μ⊕-context such that B=B[B] with Bj=μ,⊕ for all j∈1..m. Note that, since A=A[A], there exist s,t:1..n→1..n′ and
μ⊕-contexts A1,…,An such that
[TABLE]
From ⟨A,B⟩∈S and Lem. 3.18, there exists f:1..n′→1..m such that
[TABLE]
where πi is the position of the i-th hole in A′ and
ρf(i) is the position of the f(i)-th hole in B. Now we reason
as follows:
[TABLE]
Note that since Ai′=μ,⊕ for all i∈1..n′, then
A′[A′]πi=μ,⊕ too. Then, we
can assure that [[A′[A′]πi]]T=⊕ for every i∈1..n′. Similarly,
[[B[B]ρj]]T=⊕ for every j∈1..m. Thus, (s-union-t) can be applied safely.
–
⟨A,B⟩=⟨A,⊕j∈1..mBl⟩* with
⟨A,Bl⟩∈S for some l∈1..m, m>1, A=μ,⊕ and Bj=⊕ for all j∈1..m. We
call B the maximal ⊕-context defining B (i.e. B=B[B] with Bj=⊕ for every j∈1..m).*
Let B′ be the μ⊕-context such that B=B′[B′] with Bj′=μ,⊕ for all l∈1..m′ (here m′≥m). Similarly, A=A[A] but we know that
A=□ since A=μ,⊕ by hypothesis. As in the
previous case, from B=B[B], there exists s,t:1..m→1..m′
and μ⊕-contexts B1,…,Bm such that
[TABLE]
Take Bj′=Bs(j)′,…,Bt(j)′ for every j∈1..m.
Then, from ⟨A,Bl⟩∈S and Lem.3.18, there
exists f:1..n→1..m′ such that
[TABLE]
Now, from Bj′=μ,⊕ we can assure
B′[B′]ρj′=μ,⊕ for every j∈1..m′. Thus, B′[B′]ρf(1)′=μ,⊕ taking ρf(1)′=ρlτf(1) where
ρl is the position of the l-th hole in B. Finally, we can
assure both [[A]]T and
[[B′[B′]ρf(1)′]]T are non-union. We
conclude as follows (recall n=1 and A=□, thus
A[A]π1=A):
[TABLE]
•
c>0. Then:
–
⟨A,B⟩=⟨μV.A′,B⟩* and
⟨{μV.A′/V}A′,B⟩∈S. By inductive
hypothesis,*
[TABLE]
Since
⟨[[{μV.A′/V}A′]]T∣k,[[B]]T∣k⟩=⟨[[μV.A′]]T∣k,[[B]]T∣k⟩ by
Def. 3.2, we conclude.
–
⟨A,B⟩=⟨A,μW.B′⟩* and
⟨A,{μW.B′/W}B′⟩∈S and A=μ. As before, from the inductive hypothesis we get*
[TABLE]
and we conclude by Def. 3.2.
⇐)* We show that R≜{⟨A′,B′⟩∣A′,B′∈T,∀k∈N.[[A′]]T∣k⪯T[[B′]]T∣k} is Φ⪯μ-dense.*
Let ⟨A,B⟩∈R. We proceed by induction on c=#μ(A)+#μ(B). From now on we consider k>0 to avoid the border case
⟨[[A]]T∣0,[[B]]T∣0⟩=⟨∘,∘⟩.
•
c=0. Since ⟨[[A]]T∣k,[[B]]T∣k⟩∈⪯T and ⪯T=Φ⪯T(⪯T),
one of the following cases must hold:
–
⟨[[A]]T∣k,[[B]]T∣k⟩=⟨a,a⟩.
Then, since c=0 it must be the case A=a=B. Thus, by
(s-refl-al), ⟨A,B⟩∈Φ⪯μ(R).
Once again, since the outermost constructor of both A and B is not
μ, there exists A′,A′′,B′,B′′∈T such that A=A′⊃A′′ and B=B′⊃B′′ with [[A′]]T=A′,
[[A′′]]T=A′′, [[B′]]T=B′ and [[B′′]]T=B′′.
Moreover, from (12) we get ⟨B′,A′⟩,⟨A′′,B′′⟩∈R. We conclude with (s-func-al), ⟨A,B⟩∈Φ⪯μ(R).
As in the previous case, we
know there exists D,D′,A′,B′∈T such that A=D@A′,
B=D′@B′ and ⟨D,D′⟩,⟨A′,B′⟩∈R. Here we
use (s-comp-al) to conclude.
–
⟨[[A]]T∣k,[[B]]T∣k⟩=⟨⊕i∈1..nAi∣k,⊕j∈1..mBj∣k⟩*
such that n+m>2, Ai∣k,Bj∣k=⊕ and
there exists f:1..n→1..m s.t. Ai∣k⪯TBf(i)∣k.*
We distinguish two cases:
(1)
n=1. Then [[A]]T∣k=A1∣k=μ,⊕ and m>1. Moreover, by
Lem. 3.11 on B, there exists m′≤m, B,B1,…,Bm′ maximal ⊕-contexts, B1,…,Bm′=⊕ and functions s,t:1..m′→1..m such that
[TABLE]
for every l∈1..m′.
Let h∈1..m′ such that f(1)∈s(h)..t(h). From
[TABLE]
and (13)-right, we get
[TABLE]
by (s-union-t). Thus, ⟨A,Bh⟩∈R.
Finally, we have A=μ,⊕, Bl=⊕
and, since #μ(B)=0, m≥m′>1. We take f′:1..1→1..m′ such that f′(1)=h and conclude with
(13)-left, by (s-union-r-al), ⟨A,B⟩∈Φ⪯μ(R).
2. (2)
n>1. By Lem. 3.11 on A, there exists n′≤n, A,A1,…,An′ maximal ⊕-contexts,
A1,…,An′=⊕ and functions s,t:1..n′→1..n such that
[TABLE]
for every l∈1..n′.
From (14)-right, by (s-union-t) using
function f from the hypothesis, we get
[TABLE]
and thus, ⟨Al,B⟩∈R for every l∈1..n′.
Then, we conclude by (s-union-l-al) resorting to
(14)-left and the fact that A,B=μ by
hypothesis (hence n≥n′>1) and Al=⊕,
⟨A,B⟩∈Φ⪯μ(R).
•
c>0. Then we must analyze two cases:
(1)
A=μV.A′. Then [[A]]T∣k=[[{μV.A′/V}A′]]T∣k by
Def. 3.2. Thus,
⟨{μV.A′/V}A′,B⟩∈R too. We conclude by
(s-rec-l-al), ⟨A,B⟩∈Φ⪯μ(R).
2. (2)
A=μ* and B=μW.B′. Again, ⟨A,B⟩∈R implies ⟨A,{μW.B′/W}B′⟩∈R. This
time we conclude by (s-rec-r-al), ⟨A,B⟩∈Φ⪯μ(R).*
Unfortunately, the generating function determined by the rules in
Fig. 6, let us call it Φ⪯μ, is not
invertible. Notice that (s-union-r-al) overlaps with itself. For example,
c⪯μ(c⊕d)⊕(e⊕c)
belongs to two Φ⪯μ-saturated sets (*i.e. *sets X such that X⊆Φ⪯μ(X)):
However, since this is the only source of non-invertibility we easily derive
a subtype membership checking function subtype(∙,∙,∙)
that, in the case of (s-union-r-al), simply checks all cases
(Fig. 7).
4. Type Checking
A syntax-directed presentation for typing in CAP, inferring judgments of
the form Γ\leavevmode\resizebox6.88889pt3.44444pt\leavevmodeto7.09pt\vboxto5.2pt\pgfpicture\makeatletter\lower-2.59999ptto0.0pt\pgfsys@beginscope\pgfsys@invoke\definecolorpgfstrokecolorrgb0,0,0\pgfsys@color@rgb@stroke000\pgfsys@invoke\pgfsys@color@rgb@fill000\pgfsys@invoke\pgfsys@setlinewidth0.4pt\pgfsys@invoke\nullfontto0.0pt\pgfsys@beginscope\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@beginscope\pgfsys@setlinewidth0.32pt\pgfsys@setdash0.0pt\pgfsys@roundcap\pgfsys@roundjoin\pgfsys@moveto-1.19998pt1.59998pt\pgfsys@curveto-1.09998pt0.99998pt0.0pt0.09999pt0.29999pt0.0pt\pgfsys@curveto0.0pt-0.09999pt-1.09998pt-0.99998pt-1.19998pt-1.59998pt\pgfsys@stroke\pgfsys@endscope\pgfsys@beginscope\pgfsys@setdash0.0pt\pgfsys@rectcap\pgfsys@moveto0.09999pt-2.59999pt\pgfsys@lineto0.09999pt2.59999pt\pgfsys@stroke\pgfsys@endscope\pgfsys@moveto0.29999pt0.0pt\pgfsys@lineto5.23047pt0.0pt\pgfsys@stroke\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm-1.00.00.0-1.00.29999pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm1.00.00.01.05.23047pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\pgfsys@discardpath\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\lxSVG@closescope\endpgfpictures:A, may be obtained from the rules of
Fig. 3 by dropping subsumption. This
requires “hard-wiring” it back in into (t-app). Unfortunately, the naïve
syntax-directed variant:
fails to capture all the required terms. In other words, there are Γ,s
and A such that Γ⊢s:A but no A′⪯μA such that
Γ\leavevmode\resizebox6.88889pt3.44444pt\leavevmodeto6.09pt\vboxto0.4pt\pgfpicture\makeatletter\lower-0.2ptto0.0pt\pgfsys@beginscope\pgfsys@invoke\definecolorpgfstrokecolorrgb0,0,0\pgfsys@color@rgb@stroke000\pgfsys@invoke\pgfsys@color@rgb@fill000\pgfsys@invoke\pgfsys@setlinewidth0.4pt\pgfsys@invoke\nullfontto0.0pt\pgfsys@beginscope\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@moveto0.29999pt0.0pt\pgfsys@lineto5.23047pt0.0pt\pgfsys@stroke\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm-1.00.00.0-1.00.29999pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm1.00.00.01.05.23047pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\pgfsys@discardpath\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\lxSVG@closescope\endpgfpictures:A′. For example, take Γ(x)≜(c⊕e⊃d)⊕(c⊕f⊃d),
s≜xc and A≜d. More
generally, from Γ\leavevmode\resizebox6.88889pt3.44444pt\leavevmodeto6.09pt\vboxto0.4pt\pgfpicture\makeatletter\lower-0.2ptto0.0pt\pgfsys@beginscope\pgfsys@invoke\definecolorpgfstrokecolorrgb0,0,0\pgfsys@color@rgb@stroke000\pgfsys@invoke\pgfsys@color@rgb@fill000\pgfsys@invoke\pgfsys@setlinewidth0.4pt\pgfsys@invoke\nullfontto0.0pt\pgfsys@beginscope\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@moveto0.29999pt0.0pt\pgfsys@lineto5.23047pt0.0pt\pgfsys@stroke\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm-1.00.00.0-1.00.29999pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm1.00.00.01.05.23047pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\pgfsys@discardpath\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\lxSVG@closescope\endpgfpicturer:A and A⪯μ⊕i∈1..nAi⊃B we cannot infer that A is a functional type due to
the presence of union types. A complete
(Prop. 4.1) syntax directed presentation is
obtained by dropping (t-subs) from
Fig. 3 and replacing (t-abs) and
(t-app) by (t-abs-al) and (t-app-al), resp., of
Fig. 8.
Proposition 4.1**.**
(1)
If Γ\leavevmode\resizebox6.88889pt3.44444pt\leavevmodeto6.09pt\vboxto0.4pt\pgfpicture\makeatletter\lower-0.2ptto0.0pt\pgfsys@beginscope\pgfsys@invoke\definecolorpgfstrokecolorrgb0,0,0\pgfsys@color@rgb@stroke000\pgfsys@invoke\pgfsys@color@rgb@fill000\pgfsys@invoke\pgfsys@setlinewidth0.4pt\pgfsys@invoke\nullfontto0.0pt\pgfsys@beginscope\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@moveto0.29999pt0.0pt\pgfsys@lineto5.23047pt0.0pt\pgfsys@stroke\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm-1.00.00.0-1.00.29999pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm1.00.00.01.05.23047pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\pgfsys@discardpath\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\lxSVG@closescope\endpgfpictures:A, then Γ⊢s:A.
2. (2)
If Γ⊢s:A, then ∃A′ such that A′⪯μA and Γ\leavevmode\resizebox6.88889pt3.44444pt\leavevmodeto6.09pt\vboxto0.4pt\pgfpicture\makeatletter\lower-0.2ptto0.0pt\pgfsys@beginscope\pgfsys@invoke\definecolorpgfstrokecolorrgb0,0,0\pgfsys@color@rgb@stroke000\pgfsys@invoke\pgfsys@color@rgb@fill000\pgfsys@invoke\pgfsys@setlinewidth0.4pt\pgfsys@invoke\nullfontto0.0pt\pgfsys@beginscope\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@moveto0.29999pt0.0pt\pgfsys@lineto5.23047pt0.0pt\pgfsys@stroke\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm-1.00.00.0-1.00.29999pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm1.00.00.01.05.23047pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\pgfsys@discardpath\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\lxSVG@closescope\endpgfpictures:A′.
Proof 4.2**.**
(1)
By induction on Γ\leavevmode\resizebox6.88889pt3.44444pt\leavevmodeto6.09pt\vboxto0.4pt\pgfpicture\makeatletter\lower-0.2ptto0.0pt\pgfsys@beginscope\pgfsys@invoke\definecolorpgfstrokecolorrgb0,0,0\pgfsys@color@rgb@stroke000\pgfsys@invoke\pgfsys@color@rgb@fill000\pgfsys@invoke\pgfsys@setlinewidth0.4pt\pgfsys@invoke\nullfontto0.0pt\pgfsys@beginscope\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@moveto0.29999pt0.0pt\pgfsys@lineto5.23047pt0.0pt\pgfsys@stroke\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm-1.00.00.0-1.00.29999pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm1.00.00.01.05.23047pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\pgfsys@discardpath\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\lxSVG@closescope\endpgfpictures:A analyzing the last rule
applied.
•
(t-var-al), (t-const-al) and (t-comp-al) are immediate.
•
(t-abs-al): then A=⊕i∈1..nAi⊃⊕i∈1..nBi and, by hypothesis of the
rule, we have [pi:Ai]i∈1..n
compatible, θi⊢ppi:Ai, dom(θi)=fm(pi) and
Γ,θi\leavevmode\resizebox6.88889pt3.44444pt\leavevmodeto6.09pt\vboxto0.4pt\pgfpicture\makeatletter\lower-0.2ptto0.0pt\pgfsys@beginscope\pgfsys@invoke\definecolorpgfstrokecolorrgb0,0,0\pgfsys@color@rgb@stroke000\pgfsys@invoke\pgfsys@color@rgb@fill000\pgfsys@invoke\pgfsys@setlinewidth0.4pt\pgfsys@invoke\nullfontto0.0pt\pgfsys@beginscope\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@moveto0.29999pt0.0pt\pgfsys@lineto5.23047pt0.0pt\pgfsys@stroke\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm-1.00.00.0-1.00.29999pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm1.00.00.01.05.23047pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\pgfsys@discardpath\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\lxSVG@closescope\endpgfpicturesi:Bi for every i∈1..n. Then, by
inductive hypothesis, Γ,θi⊢si:Bi and, by
(t-subs), Γ,θi⊢si:⊕i∈1..nBi for each i∈1..n. Finally we conclude with (t-abs).
•
(t-app-al): then A=⊕i∈1..nBi and we have
Γ\leavevmode\resizebox6.88889pt3.44444pt\leavevmodeto6.09pt\vboxto0.4pt\pgfpicture\makeatletter\lower-0.2ptto0.0pt\pgfsys@beginscope\pgfsys@invoke\definecolorpgfstrokecolorrgb0,0,0\pgfsys@color@rgb@stroke000\pgfsys@invoke\pgfsys@color@rgb@fill000\pgfsys@invoke\pgfsys@setlinewidth0.4pt\pgfsys@invoke\nullfontto0.0pt\pgfsys@beginscope\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@moveto0.29999pt0.0pt\pgfsys@lineto5.23047pt0.0pt\pgfsys@stroke\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm-1.00.00.0-1.00.29999pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm1.00.00.01.05.23047pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\pgfsys@discardpath\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\lxSVG@closescope\endpgfpicturer:A′ and Γ\leavevmode\resizebox6.88889pt3.44444pt\leavevmodeto6.09pt\vboxto0.4pt\pgfpicture\makeatletter\lower-0.2ptto0.0pt\pgfsys@beginscope\pgfsys@invoke\definecolorpgfstrokecolorrgb0,0,0\pgfsys@color@rgb@stroke000\pgfsys@invoke\pgfsys@color@rgb@fill000\pgfsys@invoke\pgfsys@setlinewidth0.4pt\pgfsys@invoke\nullfontto0.0pt\pgfsys@beginscope\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@moveto0.29999pt0.0pt\pgfsys@lineto5.23047pt0.0pt\pgfsys@stroke\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm-1.00.00.0-1.00.29999pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm1.00.00.01.05.23047pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\pgfsys@discardpath\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\lxSVG@closescope\endpgfpictureu:C with A′≃μ⊕i∈1..n(Ai⊃Bi), Ai=⊕
and C⪯μAi for every i∈i..n. From Γ\leavevmode\resizebox6.88889pt3.44444pt\leavevmodeto6.09pt\vboxto0.4pt\pgfpicture\makeatletter\lower-0.2ptto0.0pt\pgfsys@beginscope\pgfsys@invoke\definecolorpgfstrokecolorrgb0,0,0\pgfsys@color@rgb@stroke000\pgfsys@invoke\pgfsys@color@rgb@fill000\pgfsys@invoke\pgfsys@setlinewidth0.4pt\pgfsys@invoke\nullfontto0.0pt\pgfsys@beginscope\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@moveto0.29999pt0.0pt\pgfsys@lineto5.23047pt0.0pt\pgfsys@stroke\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm-1.00.00.0-1.00.29999pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm1.00.00.01.05.23047pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\pgfsys@discardpath\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\lxSVG@closescope\endpgfpicturer:A′, by inductive hypothesis, we have Γ⊢r:A′. Moreover,
from A′≃μ⊕i∈1..n(Ai⊃Bi) with
(s-eq) and (t-subs), we get Γ⊢r:⊕i∈1..n(Ai⊃Bi). By (t-subs) once again, we deduce
[TABLE]
Now, from C⪯μAi we get Ai⊃⊕j∈1..nBj⪯μC⊃⊕j∈1..nBj for
every i∈1..n, and therefore
[TABLE]
From this and
(15) we deduce Γ⊢r:C⊃⊕i∈1..nBi using (t-subs). Finally, from Γ\leavevmode\resizebox6.88889pt3.44444pt\leavevmodeto6.09pt\vboxto0.4pt\pgfpicture\makeatletter\lower-0.2ptto0.0pt\pgfsys@beginscope\pgfsys@invoke\definecolorpgfstrokecolorrgb0,0,0\pgfsys@color@rgb@stroke000\pgfsys@invoke\pgfsys@color@rgb@fill000\pgfsys@invoke\pgfsys@setlinewidth0.4pt\pgfsys@invoke\nullfontto0.0pt\pgfsys@beginscope\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@moveto0.29999pt0.0pt\pgfsys@lineto5.23047pt0.0pt\pgfsys@stroke\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm-1.00.00.0-1.00.29999pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm1.00.00.01.05.23047pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\pgfsys@discardpath\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\lxSVG@closescope\endpgfpictureu:C and the inductive hypothesis we have Γ⊢u:C, thus we
conclude by applying (t-app), Γ⊢ru:⊕i∈1..nBi.
2. (2)
By induction on Γ⊢s:A analyzing the last rule applied.
•
(t-var), (t-const) and (t-comp) are immediate.
•
(t-abs): then A=⊕i∈1..nAi⊃B
and, by hypothesis of the rule, we have [pi:Ai]i∈1..n compatible, θi⊢ppi:Ai,
dom(θi)=fm(pi), Γ,θi⊢si:B for every
i∈1..n. Then, by inductive hypothesis, ∃Bi such that Bi⪯μB and Γ,θi\leavevmode\resizebox6.88889pt3.44444pt\leavevmodeto6.09pt\vboxto0.4pt\pgfpicture\makeatletter\lower-0.2ptto0.0pt\pgfsys@beginscope\pgfsys@invoke\definecolorpgfstrokecolorrgb0,0,0\pgfsys@color@rgb@stroke000\pgfsys@invoke\pgfsys@color@rgb@fill000\pgfsys@invoke\pgfsys@setlinewidth0.4pt\pgfsys@invoke\nullfontto0.0pt\pgfsys@beginscope\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@moveto0.29999pt0.0pt\pgfsys@lineto5.23047pt0.0pt\pgfsys@stroke\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm-1.00.00.0-1.00.29999pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm1.00.00.01.05.23047pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\pgfsys@discardpath\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\lxSVG@closescope\endpgfpicturesi:Bi for each i∈1..n. Finally we conclude by applying (t-abs-al), assigning s the
type ⊕i∈1..nAi⊃⊕i∈1..nBi. Note that ⊕i∈1..nBi⪯μB and
thus we have ⊕i∈1..nAi⊃⊕i∈1..nBi⪯μ⊕i∈1..nAi⊃B=A.
•
(t-app): then Γ⊢r:⊕i∈1..nAi⊃A and Γ⊢u:Ak for some k∈1..n. By
inductive hypothesis we have Γ\leavevmode\resizebox6.88889pt3.44444pt\leavevmodeto6.09pt\vboxto0.4pt\pgfpicture\makeatletter\lower-0.2ptto0.0pt\pgfsys@beginscope\pgfsys@invoke\definecolorpgfstrokecolorrgb0,0,0\pgfsys@color@rgb@stroke000\pgfsys@invoke\pgfsys@color@rgb@fill000\pgfsys@invoke\pgfsys@setlinewidth0.4pt\pgfsys@invoke\nullfontto0.0pt\pgfsys@beginscope\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@moveto0.29999pt0.0pt\pgfsys@lineto5.23047pt0.0pt\pgfsys@stroke\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm-1.00.00.0-1.00.29999pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm1.00.00.01.05.23047pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\pgfsys@discardpath\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\lxSVG@closescope\endpgfpicturer:B with B⪯μ⊕i∈1..nAi⊃A. Without loss of generality
we can assume B=⊕j∈1..mBj with Bj=⊕. Moreover, by contractiveness, we can further assume that B≃μ⊕j∈1..mBj and Bj=μ,⊕ for every j∈1..m.
By Prop. 3.15, from
(s-union-l-al) we get Bj⪯μ⊕i∈1..nAi⊃A for every j∈1..m. Moreover, since Bj=μ,⊕ it can only be the case of (s-func-al) thus, by
Prop. 3.15 once again, we have Bj=Bj′⊃Bj′′ with
[TABLE]
for every j∈1..m. Once again, by contractiveness we can assume Bj′=μ. Resorting to the maximal union type notation once again,
we can assume w.l.o.g that ⊕i∈1..nAi=⊕i∈1..n′Ai′ such that Ak=⊕i∈IkAi′ with Ik⊆1..n′ and Ai′=⊕ for
every i∈1..n′. Then, by
Prop. 3.15 and (s-union-l-al),
from (16-left) we get Ai′⪯μBj′ for every i∈1..n′. Hence, from Ik⊆1..n′ we deduce
[TABLE]
for every j∈1..m. By inductive hypothesis from Γ⊢u:Ak we get ∃C such that C⪯μAk and
Γ\leavevmode\resizebox6.88889pt3.44444pt\leavevmodeto6.09pt\vboxto0.4pt\pgfpicture\makeatletter\lower-0.2ptto0.0pt\pgfsys@beginscope\pgfsys@invoke\definecolorpgfstrokecolorrgb0,0,0\pgfsys@color@rgb@stroke000\pgfsys@invoke\pgfsys@color@rgb@fill000\pgfsys@invoke\pgfsys@setlinewidth0.4pt\pgfsys@invoke\nullfontto0.0pt\pgfsys@beginscope\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@moveto0.29999pt0.0pt\pgfsys@lineto5.23047pt0.0pt\pgfsys@stroke\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm-1.00.00.0-1.00.29999pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm1.00.00.01.05.23047pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\pgfsys@discardpath\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\lxSVG@closescope\endpgfpictureu:C. Then, from (17) we deduce C⪯μBj′ for every j∈1..m by transitivity of subtyping. Finally, from
(16-right) we get ⊕j∈1..mBj′′⪯μA
and we conclude with (t-app-al) since B≃μ⊕j∈1..mBj=⊕j∈1..m(Bj′⊃Bj′′).
•
(t-subs): here we have Γ⊢s:B with B⪯μA. By inductive hypothesis we get Γ\leavevmode\resizebox6.88889pt3.44444pt\leavevmodeto6.09pt\vboxto0.4pt\pgfpicture\makeatletter\lower-0.2ptto0.0pt\pgfsys@beginscope\pgfsys@invoke\definecolorpgfstrokecolorrgb0,0,0\pgfsys@color@rgb@stroke000\pgfsys@invoke\pgfsys@color@rgb@fill000\pgfsys@invoke\pgfsys@setlinewidth0.4pt\pgfsys@invoke\nullfontto0.0pt\pgfsys@beginscope\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@moveto0.29999pt0.0pt\pgfsys@lineto5.23047pt0.0pt\pgfsys@stroke\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm-1.00.00.0-1.00.29999pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm1.00.00.01.05.23047pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\pgfsys@discardpath\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\lxSVG@closescope\endpgfpictures:A′ with A′⪯B and we conclude by transitivity of subtyping.
From this we may obtain a simple type-checking function
tc(Γ,s) (Fig. 9-top) such that
tc(Γ,s)=A iff Γ\leavevmode\resizebox6.88889pt3.44444pt\leavevmodeto6.09pt\vboxto0.4pt\pgfpicture\makeatletter\lower-0.2ptto0.0pt\pgfsys@beginscope\pgfsys@invoke\definecolorpgfstrokecolorrgb0,0,0\pgfsys@color@rgb@stroke000\pgfsys@invoke\pgfsys@color@rgb@fill000\pgfsys@invoke\pgfsys@setlinewidth0.4pt\pgfsys@invoke\nullfontto0.0pt\pgfsys@beginscope\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@moveto0.29999pt0.0pt\pgfsys@lineto5.23047pt0.0pt\pgfsys@stroke\pgfsys@invoke\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm-1.00.00.0-1.00.29999pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@beginscope\pgfsys@invoke\pgfsys@transformcm1.00.00.01.05.23047pt0.0pt\pgfsys@invoke\pgfsys@invoke\lxSVG@closescope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\pgfsys@discardpath\pgfsys@invoke\lxSVG@closescope\pgfsys@endscope\hss\lxSVG@closescope\endpgfpictures:A′, for some A′≃μA. The interesting clause is that of application,
where the decision of whether (t-comp-al) or (t-app-al) may be applied
depends on the result of the recursive call. If the term r is
assigned a datatype, then a new compound datatype is built; if its type
can be rewritten as a union of functional types, then a proper type is
constructed with each of the codomains of the latter, as established in rule
(t-app-al).
Compatibility between branches is verified by checking if Pcomp(p:A,q:B) holds:
In pcomp we may assume that it has already been checked that p has
type A and q has type B. Therefore, if these are compound patterns they
can only be assigned application types, and union types may only appear at leaf
positions of a pattern. We use this correspondence to traverse both pattern and
type simultaneously in linear time, which means the worst-case execution time
of the compatibility check is governed by the complexity of subtyping.
[TABLE]
The expression unfold(A), in the clause defining
tc(Γ,ru), is the result of unfolding type A
using rules (e-rec-l-al) and (e-rec-r-al) until the result is an
equivalent type A′=⊕i∈1..nAi′ with Ai′=μ,⊕, and then simply verifying that Ai′=⊃ for all i∈1..n.
[TABLE]
Termination is guaranteed by contractiveness of μ-types. In the worst case
it requires exponential time due to the need to unfold types until the desired
equivalent form is obtained (e.g. μX1.…μXn.X1⊃…Xn⊃c).
5. Towards Efficient Type-Checking
The algorithms presented so far are clear but inefficient. The number of
recursive calls in eqtype and subtype is not bounded (it
depends on the size of the type) and unfolding recursive types may increment
their size exponentially. This section draws from ideas
in [13, 16, 7]
and adopts a dag-representation of recursive types which are encoded as
term automata (described below). Associativity is handled by resorting to n-ary
unions, commutativity and idempotence of ⊕ is handled by how types
are decomposed in their automaton representation (cf. check in
Fig. 13). The algorithm itself is
tc of Fig. 9 except that:
(1)
The representation of μ-types are now term automata. This renders
unfold linear.
2. (2)
The subtyping algorithm is optimized, based on the new representation
and following ideas
from [16, 7].
The end product is an algorithm with complexity O(n7d) where n is the
size of the input (*i.e. *that of Γ plus t) and d is the maximum arity
of the n-unions occurring in Γ and t. Note that all the information
needed to type t is either in the context or annotated within the term
itself. Thus, a linear relation can be established between the size of the
input and the size of the resulting type; and we can think of n as the size
of the latter.
5.1. Term Automata
μ-types may be
understood as finite dags since their infinite
unfolding produce a regular (infinite) trees. We further simplify the types
whose dags we consider by flattening the union type constructor and switching
to an alphabet where unions are n-ary: Ln≜{a0∣a∈V∪C}∪{@2,⊃2}∪{⊕n∣n>1} and we let Tn
stand for possibly infinite trees whose nodes are symbols in Ln.
μ-types may be interpreted in Tn simply by unfolding and then
considering maximal union types as their underlying n-ary union types. We
do so by resorting to our previous interpretation of μ-types over T
and the following translation.
Definition 5.1**.**
The function [[∙]]n:T→Tn is defined inductively as
follows:
[TABLE]
Types in Tn may be represented as term
automata [1].
Definition 5.2**.**
A term automaton is a tuple M=⟨Q,Σ,q0,δ,l⟩ where:
(1)
Q* is a finite set of states.*
2. (2)
Σ* is an alphabet where each symbol has an associated arity.*
3. (3)
q0* is the initial state.*
4. (4)
δ:Q×N→Q* is a partial transition function
between states, defined over 1..k, where k is the arity of the symbol
associated by ℓ to the origin state.*
5. (5)
ℓ:Q→Σ* is a total function that associates a symbol in
Σ to each state.*
We write MA for the automaton associated to type A. MA recognizes all
paths from the root of A to any of its sub-expressions.
Fig. 10 illustrates an example type, namely
ListA=μα.nil⊕(cons@A@α),
represented as an infinite tree and as a term automaton MListA. If
q0 is the initial state of MListA and δ denotes the
natural extension of δ to sequences of symbols, then
ℓ(δ(q0,211))=cons. As mentioned, the regular
structure of trees arising from types yields automata with a finite number of states.
5.2. Subtyping and Subtype Checking
We next present a coinductive notion of subtyping over Tn. It is a binary
relation ⪯TnRup-to a set of hypothesis R
(Fig. 11). For R=∅, ⪯TnR
coincides with ⪯μ, modulo the proper translation.
Proposition 5.3**.**
A⪯μB* iff [[[[A]]T]]n⪯Tn∅[[[[B]]T]]n.*
So we can use ⪯Tn∅ to determine whether types are related via
⪯μ: take two types, construct their automaton representation and
check whether these are related via ⪯Tn∅. Moreover, our formulation
of ⪯TnR will prove convenient for proving correctness of our
subtyping algorithm.
The proof of Prop. 5.3 resorts to
Prop. 3.16
and 5.4 below.
Proposition 5.4**.**
A⪯TB* iff [[A]]n⪯Tn∅[[B]]n.*
Proof 5.5**.**
⇒)* We prove this part by showing that R≜{⟨[[A]]n,[[B]]n⟩∣A⪯TB} is
Φ⪯Tn∅-dense. We proceed by analyzing the shape of any possible
element of R.*
•
⟨[[A]]n,[[B]]n⟩=⟨a,a⟩. Then
⟨[[A]]n,[[B]]n⟩∈Φ⪯Tn∅(R).
•
⟨[[A]]n,[[B]]n⟩=⟨T′@T′′,S′@S′′⟩. Note that the
translation of a type in T can only have symbol @ at the
root if the original type already does. Then, we know that A must be of
the form D@A′, where [[D]]n=T′ and
[[A′]]n=T′′. Similarly, we have B=D′@B′
with [[D′]]n=S′ and [[B′]]n=S′′.
By definition of R we have A⪯TB, and by rule
(s-comp-t) both D⪯TD′ and A′⪯TB′ hold.
Then ⟨[[D]]n,[[D′]]n⟩,⟨[[A′]]n,[[B′]]n⟩∈R. Thus,
⟨[[D]]n@[[A′]]n,[[D′]]n@[[B′]]n⟩∈Φ⪯Tn∅(R). Finally, by Def. 5.1, we have
[TABLE]
•
⟨[[A]]n,[[B]]n⟩=⟨T′⊃T′′,S′⊃S′′⟩. Similarly to the
previous case, by Def. 5.1, we have ⟨A,B⟩=⟨A′⊃A′′,B′⊃B′′⟩ with [[A′]]n=T′, [[A′′]]n=T′′, [[B′]]n=S′ and
[[B′′]]n=S′′. Then, from A⪯TB we get
⟨[[B′]]n,[[A′]]n⟩,⟨[[A′′]]n,[[B′′]]n⟩∈R and thus
[TABLE]
•
⟨[[A]]n,[[B]]n⟩=⟨⊕inTi,S⟩* with S=⊕. A tree of
the form ⊕inTi can only result from translating a
maximal union of n>1 elements, thus A=⊕i∈1..nAi where [[Ai]]n=Ti. On the other hand, S=⊕ implies B=⊕. From A⪯TB, by
(s-union-t), we know Ai⪯TB for every i∈1..n.
Thus, ⟨[[Ai]]n,[[B]]n⟩∈R for every i∈1..n
and we conclude*
[TABLE]
•
⟨[[A]]n,[[B]]n⟩=⟨T,⊕jmSj⟩* with T=⊕. This case
is similar to the previous one. We have A=⊕ and B=⊕j∈1..mBj with m>1 and [[Bj]]n=Sj.
From A⪯TB we know there exists k∈1..m such that A⪯TBk by rule (s-union-t). Thus,
⟨[[A]]n,[[Bj]]n⟩∈R and we conclude*
[TABLE]
•
⟨[[A]]n,[[B]]n⟩=⟨⊕inTi,⊕jmSj⟩. With a similar
argument to the two previous cases we have maximal union types A=⊕i∈1..nAi and B=⊕j∈1..mBj with [[Ai]]n=Ti and [[Bj]]n=Sj.
By (s-union-t) once again, from A⪯TB we know that there
exists a function f:1..n→1..m such that Ai⪯TBf(i)
for every i∈1..n. Thus, ⟨[[Ai]]n,[[Bf(i)]]n⟩∈R and we resort to Φ⪯Tn∅ and Def. 5.1 to
conclude
[TABLE]
⇐)* Similarly, we define R≜{⟨A,B⟩∣[[A]]n⪯Tn∅[[B]]n} and show that it is
Φ⪯T-dense. We proceed my analyzing the shape of ⟨A,B⟩∈R:*
•
⟨A,B⟩=⟨a,a⟩. Then ⟨A,B⟩∈Φ⪯T(R) trivially.
•
⟨A,B⟩=⟨D@A′,D′@B′⟩.
By Def. 5.1, ⟨[[A]]n,[[B]]n⟩=⟨[[D]]n@[[A′]]n,[[D′]]n@[[B′]]n⟩.
Moreover, since [[A]]n⪯Tn∅[[B]]n, we have
[[D]]n⪯Tn∅[[D′]]n and [[A′]]n⪯Tn∅[[B′]]n. Then, ⟨D,D′⟩,⟨A′,B′⟩∈R and
[TABLE]
•
⟨A,B⟩=⟨A′⊃A′′,B′⊃B′′⟩. As in the previous
case we resort to Def. 5.1 to get
⟨[[A]]n,[[B]]n⟩=⟨[[A′]]n⊃[[A′′]]n,[[B′]]n⊃[[B′′]]n⟩.
Then, from [[A]]n⪯Tn∅[[B]]n we get [[B′]]n⪯Tn∅[[A′]]n and [[A′′]]n⪯Tn∅[[B′′]]n
by (s-func-up). Thus, ⟨B′,A′⟩,⟨A′′,B′′⟩∈R
and
[TABLE]
•
⟨A,B⟩=⟨⊕i∈1..nAi,⊕j∈1..mBj⟩* with n+m>2 and Ai,Bi=⊕. Then we need to distinguish three cases:*
–
If m=1, then n>1 and [[A]]n=⊕in[[Ai]]n. From [[A]]n⪯Tn∅[[B]]n we have [[Ai]]n⪯Tn∅[[B]]n for
every i∈1..n, by (s-union-l-up). Then, ⟨Ai,B⟩∈R
and by definition of Φ⪯T we get
[TABLE]
–
If n=1, then m>1 and [[B]]n=⊕jm[[Bj]]n. Here, by (s-union-r-up), we have
[[A]]n⪯Tn∅[[Bk]]n for some k∈1..m, and thus
⟨A,Bk⟩∈R. Finally we conclude
[TABLE]
–
If n>1 and m>1, then both A and B are maximal union
types with at least two elements each. Here it applies (s-union-up)
and we have [[A]]n=⊕in[[Ai]]n,
[[B]]n=⊕jm[[Bj]]n, and there exists f:1..n→1..m such that [[Ai]]n⪯Tn∅[[Bf(i)]]n. Then, ⟨Ai,Bf(i)⟩∈R and we
conclude
[TABLE]
5.2.1. Algorithm Description
The algorithm that checks whether types are related by the new subtyping
relation builds on ideas from [7].
Our presentation is more general than required for subtyping; this general
scheme will also be applicable to type equivalence, as we shall later see.
Call p∈Tn×Tnvalid if p∈⪯Tn∅. The algorithm consists of two phases. The aim of the
first one is to construct a set U⊆Tn×Tn that
delimits the universe of pairs of types that will later be refined to obtain a
set of only valid pairs. It starts off with an initial pair (*cf. *Fig. 12, buildUniverse) and
then explores pairs of sub-terms of both types in this pair by decomposing the
type constructors (*cf. *Fig. 12,
children). Note that, given p, the algorithm may add invalid
pairs in order to prove the validity of p. The second phase shall be in
charge of eliminating these invalid pairs. Note that the first phase can easily be
adapted to other relations by simply redefining function children.
U may be interpreted as a directed graph where an edge from pair p to
q means that q might belong to the support set of p in the final relation
⪯Tn∅. In this case we say that p is a parent of q. Since
types could have cycles, a pair may be added to U more than once and hence
have more than one parent. Set u(p) to be the incoming degree of
p, *i.e. *the number of parents.
During the second phase (Fig. 13,
gfp) the following sets are maintained, all of which conform a
partition of U:
•
W: pairs whose validity has yet to be determined
•
S: pairs considered conditionally valid
•
F: invalid pairs
The algorithm repeatedly takes elements in W and, in each iteration,
transfers to S the selected pair p if its validity can be proved
assuming valid only those pairs which have not been discarded up until now
(*i.e. *those in W∪S). Otherwise, p is transferred to F and all of its
parents in S need to be reconsidered (their validity up-to W may have
changed). Thus these parents are moved back to W (*cf. *Fig. 13, invalidate).
Intuitively, S contains elements in ⪯TnW. The process ends when
W is empty. The only aspect of this second phase specific to ⪯TnW
is function check, which may be redefined to be other
suitable up-to relations.
5.2.2. Correctness
It is based on the fact that S may be considered a set of valid pairs
assuming the validity of those in W. More generally, the following
holds:
Proposition 5.6**.**
The algorithm preserves the following invariant:
•
⟨W,S,F⟩* is a partition of U*
•
F* is composed solely of invalid pairs*
•
S⊆Φ⪯TnW(S)**
Proof 5.7**.**
The tree conditions clearly hold at the beginning of the second phase, where W=U, and both S and F are empty. Moreover, during the process, pairs are
transferred between the three sets preserving the first condition.
Notice that, in each iteration, the decision of whether to invalidate a pair
p or move it to S is made analyzing if there are enough elements in S∪W to prove its validity (cf. Fig. 13,
check). We show this by analyzing the structure of p:
•
p=⟨a,a⟩*. As we can see in (s-refl-up), the validity of
p does not depend on any other pair (i.e. * its support set is empty). As
expected, the algorithm transfers p to S directly, without further
checks.
•
p=⟨D@A,D′@A′⟩. By
(s-comp-up), p is only valid if ⟨D,D′⟩ and
⟨A,A′⟩ also are. Those are exactly the pairs that are evaluated
to decide whether to invalidate p or not.
•
p=⟨A⊃B,A′⊃B′⟩. This case
corresponds to (s-func-up), p will be moved to S only if
⟨A′,A⟩ and ⟨B,B′⟩ has not been discarded yet.
•
p=⟨⊕inAi,⊕jmBj⟩.
Here the algorithm checks if for each Ai there exists Bj not yet
invalidated, to continue considering p a valid pair. This is exactly the
hypothesis of rule (s-union-up).
•
p=⟨⊕inAi,B⟩. Similarly, as indicated in
(s-union-l-up), the process checks that no pair ⟨Ai,B⟩ was
already invalidated.
•
p=⟨A,⊕jmBj⟩. Here, by rule
(s-union-r-up), it is enough to find a non-invalid pair
⟨A,Bj⟩ to keep p in the set of conditionally valid pairs.
If there is not enough elements in S∪W to consider p a valid pair,
then it is considered invalid and moved to F, preserving the second condition
of the invariant.
We now check the last condition. We use indexes 0 and 1 to distinguish between
the state of the sets at the beginning and end of each iteration respectively.
We consider two cases depending on the decision made on p:
•
*If p is moved to S (*i.e. all the necessary elements to prove its
validity are in W0∪S0) we have:
[TABLE]
By definition we have S0⊆Φ⪯TnW0(S0), hence
[TABLE]
Notice that
S1∪W1=S0∪W0. Then, by definition of Φ⪯TnR we
get Φ⪯TnW0(S0)=Φ⪯TnW1(S1). Thus,
[TABLE]
The set on the
left-hand side is exactly S1. Moreover, since the necessary elements to
consider p a valid pair are in S1∪W1, we have p∈Φ⪯TnW1(S1). Finally, we conclude
[TABLE]
•
If p is invalidated we have:
[TABLE]
where Q contains the parents of p that belong to S0. We proceed to
show that S1⊆Φ⪯TnW1(S1). Assume toward a
contradiction that there exists s∈S1 such that s∈/Φ⪯TnW1(S1). Then s cannot have an empty support set.
Moreover, from S1⊆S0 we know s∈S0.
On the other hand, from s∈/Φ⪯TnW1(S1) we deduce that
there exists an element in the support set of s that is not in S1∪W1 but belongs to S0∪W0, since S0 is
Φ⪯TnW0(S0)-dense. By the equalities above, the only possible
such element is p. Thus, s is a parent of p. Given that the algorithm
moves to W1 all the parents of p that belong to S0, we should have s∈W1. This leads to a contradiction since s∈S1 and the sets W1,S1,F1 form a partition of U.
The contradiction comes from assuming the existence of such s, hence we
conclude
[TABLE]
When the main cycle ends we know that W is empty, and therefore that S⊆Φ⪯Tn∅(S). The coinduction principle then
yields S⊆⪯Tn∅ (*i.e. * every pair in S is valid) and
therefore we are left to verify whether the original pair of types is in S
or F.
5.2.3. Complexity
The first phase consists of identifying relevant pairs of sub-terms in both
types being evaluated. If we call N and N′ the size of such types
(considering nodes and edges in their representations) we have that the size
and cost of building the universe U can be bounded by O(NN′). As we shall
see, the total cost of the algorithm is governed by the amount of operations in
the second phase.
As stated in [7], since any pair can be
invalidated at most once (in which case u(p) nodes are transferred back to
W for reconsideration) the amount of iterations in the refinement stage can
be bounded by
[TABLE]
Assuming that set operations can be performed in constant time, the cost of
evaluating each node in the main loop is that of deciding whether to suspend or
invalidate the pair and, in the later case, the cost of the invalidation
process. The decision of where to transfer the node is computed in the function
check, which always performs a constant amount of operations for pairs
of non-union types. The worst case involves checking pairs of the form
⟨⊕inAi,⊕jmBi⟩, which can be resolved by
maintaining in each node a table indicating, for every Ai, the amount of
pairs ⟨Ai,Bj⟩ that have not yet been invalidated. Using this approach,
this check can be performed in O(d) operations, where d is a bound on the
size of both unions. Whenever a pair is invalidated, all tables present in its
immediate parents are updated as necessary.
Finally we resort to an argument introduced
in [7] to argue that the cost of
invalidating an element can be seen as O(1): a new iteration will be
performed for each of the u(p) pairs added to W when invalidating p.
Because of this, a more precise bound for the cost of the complete execution of
the algorithm can be obtained if we consider the cost of adding each of these
elements to W as part of the iteration itself, yielding an amortized cost of
O(d) operations for each iteration. This leaves a total cost of O(size(U)d) for the subtyping check, expressed as O(NN′d) in terms of the size of
the input automata.
Let us call n and n′ the amount of constructors in types A and B,
respectively. N and N′ are the sizes of automata representing these types,
and can consequently be bounded by O(n2) and O(n′2). Therefore, the
complexity of the algorithm can be expressed as O(n2n′2d).
5.3. Equivalence Checking
In this section we adapt the previous algorithm to obtain one proper of
equivalence checking with the same complexity cost.
Fig. 15 introduces an equivalence relation
up-toR over Tn which can be used to compute ≃μ via
the translation [[∙]]n.
Proposition 5.8**.**
A≃μB* iff [[[[A]]T]]n≃Tn∅[[[[B]]T]]n.*
As done before for subtyping, we prove this by resorting to
Prop. 3.5
and 5.9 below:
Proposition 5.9**.**
A≃TB* iff [[A]]n≃Tn∅[[B]]n.*
Proof 5.10**.**
⇒)*
We prove this part by showing that R≜{⟨[[A]]n,[[B]]n⟩∣A≃TB} is
Φ≃Tn∅-dense. We proceed by analyzing the shape of any possible
element of R.*
•
⟨[[A]]n,[[B]]n⟩=⟨a,a⟩. Then
⟨[[A]]n,[[B]]n⟩∈Φ≃Tn∅(R).
•
⟨[[A]]n,[[B]]n⟩=⟨T′@T′′,S′@S′′⟩. Note that the
translation of a type in T can only have symbol @ at the
root if the original type already does. Then, we know that A must be of
the form D@A′, where [[D]]n=T′ and
[[A′]]n=T′′. Similarly, we have B=D′@B′
with [[D′]]n=S′ and [[B′]]n=S′′.
By definition of R we have A≃TB, and by rule
(e-comp-t) both D≃TD′ and A′≃TB′ hold.
Then ⟨[[D]]n,[[D′]]n⟩,⟨[[A′]]n,[[B′]]n⟩∈R. Thus,
⟨[[D]]n@[[A′]]n,[[D′]]n@[[B′]]n⟩∈Φ≃Tn∅(R). Finally, by Def. 5.1, we have
[TABLE]
•
⟨[[A]]n,[[B]]n⟩=⟨T′⊃T′′,S′⊃S′′⟩. Similarly to the
previous case, by Def. 5.1, we have ⟨A,B⟩=⟨A′⊃A′′,B′⊃B′′⟩ with [[A′]]n=T′, [[A′′]]n=T′′, [[B′]]n=S′ and
[[B′′]]n=S′′. Then, from A≃TB we get
⟨[[A′]]n,[[B′]]n⟩,⟨[[A′′]]n,[[B′′]]n⟩∈R and thus
[TABLE]
•
⟨[[A]]n,[[B]]n⟩=⟨⊕inTi,S⟩* with S=⊕. A tree of
the form ⊕inTi can only result from translating a
maximal union of n>1 elements, thus A=⊕i∈1..nAi where [[Ai]]n=Ti. On the other hand, S=⊕ implies B=⊕. From A≃TB, by
(e-union-t), we know Ai≃TB for every i∈1..n.
Thus, ⟨[[Ai]]n,[[B]]n⟩∈R for every i∈1..n
and we conclude*
[TABLE]
•
⟨[[A]]n,[[B]]n⟩=⟨T,⊕jmSj⟩* with T=⊕. This case
is similar to the previous one. We have A=⊕ and B=⊕j∈1..mBj with m>1 and [[Bj]]n=Sj.
From A≃TB we know, by (e-union-t), that A≃TBj for every j∈1..m. Thus, ⟨[[A]]n,[[Bj]]n⟩∈R and we conclude*
[TABLE]
•
⟨[[A]]n,[[B]]n⟩=⟨⊕inTi,⊕jmSj⟩. With a similar
argument to the two previous cases we have maximal union types A=⊕i∈1..nAi and B=⊕j∈1..mBj with [[Ai]]n=Ti and [[Bj]]n=Sj.
By (e-union-t) once again, from A≃TB we know that there
exists a function
[TABLE]
Thus, ⟨[[Ai]]n,[[Bf(i)]]n⟩,⟨[[Ag(j)]]n,[[Bj]]n⟩∈R. and we resort to
Φ≃Tn∅ and Def. 5.1 to
conclude
[TABLE]
⇐)* Similarly, we define R≜{⟨A,B⟩∣[[A]]n≃Tn∅[[B]]n} and show that it is
Φ≃T-dense. We proceed my analyzing the shape of ⟨A,B⟩∈R:*
•
⟨A,B⟩=⟨a,a⟩. Then ⟨A,B⟩∈Φ≃T(R) trivially.
•
⟨A,B⟩=⟨D@A′,D′@B′⟩.
By Def 5.1, ⟨[[A]]n,[[B]]n⟩=⟨[[D]]n@[[A′]]n,[[D′]]n@[[B′]]n⟩.
Moreover, since [[A]]n≃Tn∅[[B]]n, we have
[[D]]n≃Tn∅[[D′]]n and [[A′]]n≃Tn∅[[B′]]n. Then ⟨D,D′⟩,⟨A′,B′⟩∈R and
[TABLE]
•
⟨A,B⟩=⟨A′⊃A′′,B′⊃B′′⟩. As in the previous
case we resort to Def. 5.1 to get
⟨[[A]]n,[[B]]n⟩=⟨[[A′]]n⊃[[A′′]]n,[[B′]]n⊃[[B′′]]n⟩.
Then, from [[A]]n≃Tn∅[[B]]n we get [[A′]]n≃Tn∅[[B′]]n and [[A′′]]n≃Tn∅[[B′′]]n,
by (e-func-up). Thus, ⟨A′,B′⟩,⟨A′′,B′′⟩∈R
and
[TABLE]
•
⟨A,B⟩=⟨⊕i∈1..nAi,⊕j∈1..mBj⟩* with n+m>2 and Ai,Bi=⊕. Then we need to distinguish three cases:*
–
If m=1, then n>1 and [[A]]n=⊕in[[Ai]]n. From [[A]]n≃Tn∅[[B]]n we have [[Ai]]n≃Tn∅[[B]]n for every
i∈1..n, by (e-union-l-up). Then, ⟨Ai,B⟩∈R. and
by definition of Φ≃T we get
[TABLE]
–
If n=1, then m>1 and [[B]]n=⊕jm[[Bj]]n. Here, by (e-union-r-up), we have
[[A]]n≃Tn∅[[Bj]]n for every j∈1..m, and thus
⟨A,Bj⟩∈R. Finally we conclude
[TABLE]
–
If n>1 and m>1, then both A and B are maximal union
types with at least two elements each. Here it applies (e-union-up) and
we have [[A]]n=⊕in[[Ai]]n,
[[B]]n=⊕jm[[Bj]]n, and there exists
[TABLE]
Then, ⟨Ai,Bf(i)⟩,⟨Ag(j),Bj⟩∈R and we
conclude
[TABLE]
The algorithm is the result of adapting the scheme presented for
subtyping to the new relation ⪯μR. This is done by redefining
functions children and check from the first and second
phase respectively (*cf. *Fig. 16). For the former
the only difference is on rule (e-func-up), where we need to add pair
⟨A′,B′⟩ instead of ⟨B′,A′⟩, added for subtyping. We
could have omitted this by using the same rule for functional types as before
and resorting to the symmetry of the resulting relation (which does not depend
on this rule), but we wanted to emphasize the fact that phase one can easily be
adapted if needed. For the refinement phase we need to properly check the
premises of rules (e-union-up) and (e-union-r-up), while the others
remain the same.
With these considerations is easy to see that, in each iteration, S consists
of pairs in the relation ≃TnW, getting S⊆≃Tn∅ at the end of the process.
Proposition 5.11**.**
The algorithm preserves the following invariant:
•
⟨W,S,F⟩* is a partition of U*
•
F* is composed solely of invalid pairs*
•
S⊆Φ≃TnW(S)**
Proof 5.12**.**
Analysis here is exactly the same as the case for subtyping. The only
difference is when proving the second condition. For that, we just need to
make sure that pairs are considered valid according to the rules of
Fig.15. We present next the cases that differ
between ⪯TnW and ≃TnW:
•
p=⟨A⊃B,A′⊃B′⟩*. This case
corresponds to (e-func-up). Here the algorithm checks for
⟨A,A′⟩ instead of ⟨A′,A⟩. That is the reason why
children was redefined (*cf. Fig. 16).
•
p=⟨⊕inAi,⊕jmBj⟩. In the
case of subtyping, the algorithm checks if for each Ai there exists
Bj not yet invalidated, to assure the existence of f (cf. (s-union-up)). Here it extends the check to verify that for each Bj
there is a Ai not yet invalidating, thus assuring the existence of g
too (cf. (e-union-up)).
•
p=⟨A,⊕jmBj⟩. Here, by rule
(e-union-r-up), there must be a pair ⟨A,Bj⟩ in S∪W for
each j∈1..m, to keep p in the set of conditionally valid pairs.
For the complexity analysis, notice that the size of the built universe is the
same as before and phase one is governed by phase two, which has at most
O(NN′) iterations. For the cost of each iteration it is enough to analyze
the complexity of check, since the rest of the scheme remains the same.
As we remarked before, the only difference in check between subtyping
and equality is in the cases involving unions. Here the worst case is when
checking rule (e-union-up) that requires the existence of two functions f
and g relating elements of each type. This can be done in linear time by
maintaining tables with the count of non-invalidated pairs of descendants, as
indicated in Sec. 5.2.3. Thus, the cost of an iteration
is O(d), resulting in an overall cost of O(NN′d) as before.
5.4. Type Checking
Let us revisit type-checking (tc). As already discussed,
it linearly traverses the input term, the most costly operations
being those that deal with application and abstraction. These cases involve
calling subtype. Notice that these calls do not depend directly on
the input to tc. However, a linear correspondence can be
established between the size of the types being considered in subtype
and the input to the algorithm, since such expressions are built from elements
of Γ (the input context) or from annotations in the input term itself.
Consider for instance subtype(∅,A,B) with a and b the size
of each type resp. This has complexity O(a2b2d) and, from the
discussion above, we can refer to it as O(n4d), where n is the size of the input
to tc (*i.e. *that of Γ plus t). Similarly, we may say
that unfold is linear in n.
We now analyze the application and abstraction cases of the algorithm in
detail:
**Application: **
First it performs a linear check on the type to verify if it is a datatype.
If so it returns. Otherwise, a second linear check is required
(unfold) in order to then perform as many calls to subtype as
elements there are in the union of the functional types. This yields a local
complexity of O(n4d2).
**Abstraction: **
First there are as many calls to tcp (the algorithm for
type-checking patterns) as branches the abstraction has. Note that
tcp has linear complexity in the size of its input and this
call is instantiated with arguments pi and θi which occur in the
original term. All these calls, taken together, may thus be considered to
have linear time complexity with respect to the input of tcp.
Then it is necessary to perform a quadratic number (in the number of
branches) of checks on compatibility. We have already analyzed that
compatibility in the worst case involves checking subtyping. If we assume a
linear number of branches w.r.t. the input, we obtain a total complexity of
O(n6d) for this case.
Finally, the total complexity of tc is governed by the case of
the abstraction, and is therefore O(n7d).
5.5. Prototype implementation
A prototype in Scala is available [10]. It implements
tc but resorts to the efficient algorithm for subtyping and type
equivalence described above. It also includes further optimizations. For
example, following a suggestion in [7], the
order in which elements in W are selected for evaluation relies on detecting
strongly connected components, using
Tarjan’s [9] algorithm of linear cost and
topologically sorting them in reverse order. In the absence of cycles this
results in evaluating every pair only after all its children have already been
considered. For cyclic types pairs for which no order can be determined are
encapsulated within the same strongly connected component.
6. Conclusions
We address efficient type-checking for path polymorphism. We start off with the
type system of [19] which includes singleton types, union types,
type application and recursive types. The union type constructor is assumed
associative, commutative and idempotent. First we formulate a syntax-directed
presentation. Then we devise invertible coinductive presentations of
type-equivalence and subtyping. This yields a naïve but correct type-checking
algorithm. However, it proves to be inefficient (exponential in the size of the
type). This prompts us to change the representation of type expressions and use
automata techniques to considerably improve the efficiency. Indeed, the final
algorithm has complexity O(n7d) where n is the size of the input and d
is the maximum arity of the unions occurring in it.
Regarding future work an outline of possible avenues follows. These are aimed
at enhancing the expressiveness of CAP itself and then adapting the
techniques presented here to obtain efficient type checking algorithms.
•
Addition of parametric polymorphism (presumably in the style of
F*<:* [5, 17, 6]). We
believe this should not present major difficulties.
•
Strong normalization requires devising a notion of positive/negative
occurrence in the presence of strong μ-type equality, which is known not
to be obvious [2, page 515].
•
A more ambitious extension is that of dynamic patterns, namely
patterns that may be computed at run-time, PPC being the prime example of a
calculus supporting this feature.
Bibliography21
The reference list from the paper itself. Each links out to its DOI / PubMed record.
1[1] Roberto M. Amadio and Luca Cardelli. Subtyping recursive types. ACM Trans. Program. Lang. Syst. , 15(4):575–631, 1993.
2[2] Hendrik Pieter Barendregt, Wil Dekkers, and Richard Statman. Lambda Calculus with Types . Perspectives in logic. Cambridge University Press, 2013. URL: http://www.cambridge.org/de/academic/subjects/mathematics/logic-categories-and-sets/lambda-calculus-types .
3[3] Marc Bezem, Jan Willem Klop, and Roel de Vrijer, editors. Term Rewriting Seminar – Terese . Cambridge University Press, 2003.
4[4] Michael Brandt and Fritz Henglein. Coinductive axiomatization of recursive type equality and subtyping. In Philippe de Groote, editor, Typed Lambda Calculi and Applications, Third International Conference on Typed Lambda Calculi and Applications, TLCA ’97, Nancy, France, April 2-4, 1997, Proceedings , volume 1210 of Lecture Notes in Computer Science , pages 63–81. Springer, 1997. URL: http://dx.doi.org/10.1007/3-540-62688-3_29 , doi:10.1007/3-540-62688-3_29 . · doi ↗
5[5] Luca Cardelli, Simone Martini, John C. Mitchell, and Andre Scedrov. An extension of system F with subtyping. In Takayasu Ito and Albert R. Meyer, editors, Theoretical Aspects of Computer Software, International Conference TACS ’91, Sendai, Japan, September 24-27, 1991, Proceedings , volume 526 of Lecture Notes in Computer Science , pages 750–770. Springer, 1991. URL: http://dx.doi.org/10.1007/3-540-54415-1_73 , doi:10.1007/3-540-54415-1_73 . · doi ↗
6[6] Dario Colazzo and Giorgio Ghelli. Subtyping recursion and parametric polymorphism in kernel fun. Inf. Comput. , 198(2):71–147, 2005. URL: http://dx.doi.org/10.1016/j.ic.2004.11.003 , doi:10.1016/j.ic.2004.11.003 . · doi ↗
7[7] Roberto Di Cosmo, François Pottier, and Didier Rémy. Subtyping recursive types modulo associative commutative products. In Pawel Urzyczyn, editor, Typed Lambda Calculi and Applications, 7th International Conference, TLCA 2005, Nara, Japan, April 21-23, 2005, Proceedings , volume 3461 of Lecture Notes in Computer Science , pages 179–193. Springer, 2005. URL: http://dx.doi.org/10.1007/11417170_14 , doi:10.1007/11417170_14 . · doi ↗
8[8] Bruno Courcelle. Fundamental properties of infinite trees. Theor. Comput. Sci. , 25:95–169, 1983. URL: http://dx.doi.org/10.1016/0304-3975(83)90059-2 , doi:10.1016/0304-3975(83)90059-2 . · doi ↗