0% found this document useful (0 votes)
72 views96 pages

Yale University Department of Computer Science

This technical report discusses using temporal logic to develop a functional calculus for the logical framework LF. It presents a meta-logic called LhiΠ for reasoning about LF objects. Key points include: 1) LhiΠ defines a logic for LF that separates representation (LF objects) and computation into different function spaces. 2) A temporal meta-logic is then defined to reason about higher-order abstract syntax represented in LF. 3) Examples are given of how natural language expressions, lambda terms, and natural deduction derivations can be represented in LF.

Uploaded by

jbapple
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
72 views96 pages

Yale University Department of Computer Science

This technical report discusses using temporal logic to develop a functional calculus for the logical framework LF. It presents a meta-logic called LhiΠ for reasoning about LF objects. Key points include: 1) LhiΠ defines a logic for LF that separates representation (LF objects) and computation into different function spaces. 2) A temporal meta-logic is then defined to reason about higher-order abstract syntax represented in LF. 3) Examples are given of how natural language expressions, lambda terms, and natural deduction derivations can be represented in LF.

Uploaded by

jbapple
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 96

Yale University

Department of Computer Science

A Temporal-Logic Approach to Functional Calculi for


Dependent Types and Higher-Order Encodings

Adam Poswolsky

YALEU/DCS/TR-1364
July 2006
A Temporal-Logic Approach to
Functional Calculi for Dependent Types
and Higher-Order Encodings
Adam Poswolsky∗

Abstract
Dependent-types and higher-order encodings lead to concise and
elegant representations of complex data structures as evidenced by the
success of the logical framework LF [HHP93].
In this work we first design a functional calculus utilizing LF to
represent its data objects. To avoid problems commonly associated
with using the same function space for both representation (LF objects)
and computation, we separate the two as influenced by our previous
work [Sch05]. We then exploit the power of the past time connective
from temporal logic to design a meta-logic to reason about higher-
order abstract syntax. Sample programs that we discuss in this paper
include bracket abstraction and a theorem prover.
It is important to note that this technical report is an enhancement/
simplification of a previous technical report [Pos06] where past-time
was used as a modal operator in the meta-logic for LF. Here, we use
past-time on the meta-meta-level for LF.

1 Introduction
Temporal extensions of logics have proved useful for binding time analy-
sis [Dav96] and meta-programming [Tah04]. In this paper we show how
temporal logic can be used to develop a calculus with functions ranging over
the usual dependently typed and higher-order encodings of deductive sys-
tems in the logical framework LF [HHP93, Pfe99]. This technical report is
an enhancement/ simplification of a previous technical report [Pos06] where
past-time was used as a modal operator in the meta-logic for LF. Here, we
use past-time on the meta-meta-level for LF.

Department of Computer Science, Yale University, CT

1
Dependent datatypes allow for type systems that are more expressive
than their simply-typed counterparts as types may be indexed by expres-
sions. For example, a list type could be indexed by its length, or a certificate
type could be indexed by the formula it is witnessing.
Both higher-order encodings, or higher-order abstract syntax (HOAS),
and hypothetical judgments employ functional abstraction of the logical
framework to model variable binding. This permits programmers to program
efficiently with complex data-structures without having to worry about the
representation of variables, binding constructs, or substitutions that are
prevalent in logic derivations, typing derivations, operational semantics, and
intermediate languages.
The challenge in designing a functional calculus for LF is that it must
provide two different function spaces [SDP01, Sch05]. In Section 2, we begin
by defining the logical framework LF. We then give a first-order meta-logic
for LF and prove soundness.
Rather than use temporal logic to represent propositions occurring at
different times, we use it to represent derivations occurring at different times.
To this end our temporal logic serves as a meta logic for the logic defined in
Section 2. We define our temporal meta logic in Section 3, discuss properties,
and prove soundness. All proofs in this paper have been encoded and verified
in Twelf [PS99] except that the underlying calculus is the simply-typed
version. Twelf code is digitally available upon request and can also be read
in Appendix A.
In Section 4, we discuss how the resulting calculus handles functions
over higher-order abstract encodings. The operators for programming with
higher-order abstract syntax correspond to admissible rules. This allows us
to statically reason about when parameters can be accessed. This compile-
time guarantee that parameters cannot escape their scope is the driving
force of this work. Current research with coverage checking and termination
checking will allow us to statically check that all cases are covered and
hence cumulatively get a static guarantee that a function is total without
the cumbersome caveat of possible runtime exceptions.
Next we derive a logically equivalent, but motivated for programming,
system in Section 5. In Section 6 we add a mechanism to conduct case
analysis, and finally in Section 7 we add recursion.
We illustrate the resulting λD calculus, or Delphin, with examples of
bracket abstraction and theorem proving in Section 8. We describe related
work in Section 9 before we conclude and assess results in Section 10.
Finally we invite the reader to consult the Delphin homepage for more
information: www.cs.yale.edu/∼delphin.

2
2 Meta-Logic for Dependently-Typed LF
We will start with a brief introduction to the Edinburgh logical frame-
work [HHP93], or LF, and then discuss our logic LhiΠ to reason about LF
objects.
We will define syntactic categories of objects M and types A to which
we assign the usual logic meaning. In our system we provide a clean divide
between the meta-level (computation) and the representation-level (LF).
The justification for this design is based on our previous work with the ∇-
calculus [Sch05], but simply stated it is necessary because we cannot reason
about arbitrary functions on the meta-level so our system syntactically en-
forces that representation-level functions cannot see computation-level ones.
We say hAi is true if and only if the type A is inhabited. If M is the witness
of inhabitation, we interpret M as a proof of hAi.

2.1 Preliminaries
Types are defined as: A, B ::= a | A M | Πx : A .B. Function types assign
names to their arguments in Πx : A .B. We reserve the notation A → B
as syntactic sugar when the return type is not dependent on its argument.
Types may be indexed by objects and we provide the construct A M to
represent such types. The syntactic category for objects is: M, N ::= x |
c | M N | λx : A .N . We write x for variables while a and c are type and
object constants, respectively. These constants are provided a priori in a
collection Σ ::= · | Σ, a : type | Σ, c : A. This should be seen as datatype
declaration, keeping in mind that our notion of datatype is non-standard
as we permit higher-order functions to be passed to constants without the
usual restriction that variables of the datatype that is being defined cannot
occur in negative positions.
With dependent types, not all types are valid. The kind system of
LF acts as a type system for types. Valid kinds are defined a follows:
K ::= type | Πx : A .K. The typing rules and kinding rules of LF may
not be as well-known as those of the simply typed λ-calculus, but they are
standard [HHP93]. We write Γ ` M : A for valid objects and Γ ` A : K for
valid types, in context Γ ::= · | Γ, x : A which assigns types to variables. We
take βη as the underlying notion of equivalence between λ-terms. Terms in
β-normal η-long form are also called canonical forms.

Theorem 2.1 (Canonical forms) Every well-typed object in the dependently-


typed λ-calculus possesses a unique canonical form.

3
The existence of canonical forms is instrumental for encodings to be
adequate, which means that there exists a bijection between expressions of
the source language and their representations (as canonical forms) in the
logical framework.

Example 2.2 (Expressions) As a sample signature, we choose the stan-


dard language of untyped λ terms t ::= x | lam x. t | t1 @t2 . In the simply
typed logical framework an expression t can be encoded as ptq, which gives
rise to the following signature.
exp : type,
pxq =x
plam x. tq = lam (λx : exp .ptq) lam : (exp → exp) → exp,
pt1 @t2 q = app pt1 q pt2 q app : exp → exp → exp

Theorem 2.3 (Adequacy) There exists a bijection between untyped λ-


terms t with free variables among x1 . . . xn and canonical derivations in the
simply typed logical framework of x1 : exp . . . xn : exp ` ptq : exp.

Proof: By induction over the structure of t in one direction and the struc-
ture of the β-normal η-long form of ptq in the other. 

Example 2.4 (Natural deduction calculus) Let A, B ::= A ⇒ B | p


be the language of formulas.
o : type,
pA ⇒ Bq = pAq ⇒ pBq ⇒: o → o → o
We write D ::` A if D is a derivation in the natural deduction calculus. ` A
is a hypothetical judgment as impi shows below.
u
`A
..
.
`B `A `A⇒B
impi impe
`A⇒B `B
Natural deduction derivation D ::` A are encoded in LF as pDq : nd pAq,
which gives rise to the following signature.
nd : o → type,
impi : (nd A → nd B) → nd (A ⇒ B),
impe : nd (A ⇒ B) → nd A → nd B.

4
Theorem 2.5 (Substitution [HHP93]) If Γ, x : A ` B : K and Γ ` M :
A then Γ ` [M/x]B : [M/x]K.

The dependently typed logical framework is elegantly designed for rep-


resentation. For instance, it permits adequate encodings of proof systems,
type systems, and operational semantics that arise in logic design and pro-
gramming languages theory. Hence, we next design a logic adopting LF to
represent its datatypes.

2.2 Meta Logic, LhiΠ


We derive our meta-logic from the sequent calculus for the implicational
fragment of propositional logic with hAi. We write Ω ` τ for the central
derivability judgment and we cannot permit reorderings of Ω because of
dependencies. In a slight abuse of notation, we write Ω1 , Ω2 for the concate-
nation of two contexts.

τ, σ, % ::= Πu ∈ τ .σ | Σu ∈ τ .σ | > | ⊥ | hAi


Our context, Ω ::= · | Ω, u ∈ τ is simply a collection of τ ’s. As already
stated, we write hAi to indicate that A is an inhabited type in our logical
framework. For functional types we use Πu ∈ τ .σ (not to be confused with
LF’s dependent function type Πx : A .B). Similarly, we use Σu ∈ τ .σ for
dependent products. We will also reserve the notation τ ⊃ σ and τ ? σ
as syntactic sugar for non-dependent versions of functions and products,
respectively.
Expressions are defined as:
e, f ::= u | unit | void u
| λu ∈ τ .e | let w = u · e in f
| (e1 e2 ) | let (w1 , w2 ) = u in e
|M
The proof term algebra almost resembles the λ-calculus. Variables are rep-
resented by u, w. Instead of application, we use the more awkward look-
ing, yet cleanly motivated let w = u · e inf . Similarly for pairs we use
let (w1 , w2 ) = u in e. As discussed earlier, M is the witness to hAi.
We write [e/u]τ as notation for an explicit substitution on the depen-
dent types. In addition, we define [e/u]Ω = Ω0 , where Ω0 is formed by
transforming every (w ∈ σ) in Ω into (w ∈ ([e/u]σ)) in Ω0
In addition, and most importantly, is how we reason about LF. We define
[Ω]LF as an operation which takes our meta-context, Ω, and converts it into

5
a context, Γ, suitable for the logical framework by simply filtering out any
meta-information. The resulting context is of the form:

Γ ::= · | Γ, u : A

We call this operation thinning and define it as follows.

Definition 2.6 (Thinning)



 · if Ω = ·
 0
[Ω ]LF , u : A if Ω = Ω0 , u ∈ hAi

[Ω]LF =

 [Ω0 ]LF if Ω = Ω0 , u ∈ τ and τ 6= hAi

An alternative approach would use two contexts, Ω and Γ, and have an


explicit construct to introduce declarations into Γ.However, this computa-
tional construct would have to be duplicated on the type-level now forcing
us to handle computation on the type-level. We have previously studied
such a construct taken the form of let hxi = u in e, but find the elegance
of keeping the type-level computation free justification enough. In addition,
with this paradigm we have that dependencies only occur on LF-objects
instead of opening a can of worms by permitting dependencies on arbitrary
expressions.
By disallowing dependencies on arbitrary expressions we must point out
that substitution on types is not defined everywhere. If a function is de-
pendent upon its argument, then its argument must be a variable or an LF
object, otherwise we cannot express its type unless if we were to add an
ominous let on the type-level. For example, from Example 2.4 we can imag-
ine a function f ∈ Πu ∈ hoi .hnd ui. This function can only be called on a
variable or on an expression M . Assuming that e is neither a variable nor
an LF expression, then although we cannot apply f directly to e, we can do
(with syntactic sugar defined later) let x = e in (f x). Here we explicitly
provide a disconnect between e and x. The alternative of having the let on
the type-level is impractical because that would also entail reasoning about
equality over arbitrary expressions to decide if types are equal.

6
[e/u]> = >
[e/u]⊥ = ⊥
[e/u](Πu ∈ τ .σ) = Πu0 ∈ [e/u]τ .[e/u]σ
0

[e/u](Σu0 ∈ τ .σ) = Σu0 ∈ [e/u]τ .[e/u]σ


[M/u]hAi = h[M/u]LF N i
[e/u]τ, u not free in τ = τ
None of the above match, [e/u]τ = undefined

Here notice that we just push our substitution to LF substitution of the


form [M/u]LF N . This is the only place that dependencies can occur. Just
as dependent-types caused us to be concerned with ill-formed LF types, we
now need to distinguish between well-formed and ill-formed formulas. We
write Ω ` τ wff for well-formed formulas.
>wff ⊥wff
Ω ` > wff Ω ` ⊥ wff
Ω ` τ wff Ω, u ∈ τ ` σ wff
ΠwffR
Ω ` Πu ∈ τ .σ wff
Ω ` τ wff Ω, u ∈ τ ` σ wff
ΣwffR
Ω ` Σu ∈ τ .σ wff
[Ω]LF ` A : type
hiwffR
Ω ` hAi wff

The main work is handled in hiwffR which utilizes thinning to appeal to


LF’s wff relation. All other cases are standard.

Theorem 2.7 (Admissibility of cutT) If D :: Ω1 ` e ∈ τ and E ::


Ω1 , u ∈ τ, Ω2 ` % wff and [e/u]Ω2 is defined and [e/u]% is defined, then
Ω1 , [e/u]Ω2 ` [e/u]% wff.

Proof: This proof goes by induction over derivation E utilizing the defini-
tion of [e/u]%. 

With this refined notion of formulas and a notion of formula level reduc-
tion, we now present LhiΠ . Note that an important implicit condition on all

7
the rules is that all elements of Ω are well-formed, as well as the resulting
type.

(u ∈ τ ) in Ω
ax
Ω`u∈τ
>R
Ω ` unit ∈ > no rule >L
⊥L
no rule ⊥R Ω1 , u ∈ ⊥, Ω2 ` void u ∈ σ
Ω, u ∈ τ ` e ∈ σ
ΠR
Ω ` λu ∈ τ .e ∈ Πu ∈ τ .σ

Ω1 , u ∈ (Πu0 ∈ τ .σ), Ω2 ` e ∈ τ
Ω1 , u ∈ (Πu0 ∈ τ .σ), Ω2 , w ∈ [e/u0 ]σ ` f ∈ %
ΠL
Ω1 , u ∈ (Πu0 ∈ τ .σ), Ω2 ` let w = u · e in f ∈ %
Ω ` e1 ∈ τ Ω ` e2 ∈ [e1 /u]σ
ΣR
Ω ` (e1 , e2 ) ∈ Σu ∈ τ .σ

Ω1 , u ∈ (Σu0 ∈ τ .σ), Ω2 , w1 ∈ τ, w2 ∈ [w1 /u0 ]σ ` e ∈ %


ΣL
Ω1 , u ∈ (Σu0 ∈ τ .σ), Ω2 ` let (w1 , w2 ) = u in e ∈ %
[Ω]LF ` M : A
hiR
Ω ` M ∈ hAi

All rules are standard except for hiR. This is the rule that drives the
system by bridging LF. One would notice that there is no corresponding L
rule. The reason for this is that it is handled by the thinning of the context.
The other rules handle dependencies standardly but by this design they
simply are pushing the dependencies to be handled by hiR and hiwffR.
The cut-rule (where substitution is defined) is admissible for this calcu-
lus.
[e/u]Ω2 is defined [e/u]σ is defined
Ω1 ` e ∈ τ Ω1 , u ∈ τ, Ω2 ` f ∈ σ
cut
Ω1 , [e/u]Ω2 ` [e/u]f ∈ [e/u]σ

8
2.3 Preliminaries
Before proving the admissibility of cut, we need some lemmas relating to
substitution.
Although the definition of substitution on expressions is determined by
the cut proof, we present it first since we will use it to prove some lemmas
regarding substitution.
[e/u]u ≡ e
0 0
[ λu ∈τ .e ]e 0
[(λu0 ∈ τ .e0 )/u] [ u
u0
]e λu0 ∈ τ .e0
≡ [ ]([ ]f )
(let w = u · e in f ) w u
[M/u]N ≡ [M/u]LF N
[(e1 , e2 )/u] [[[e2 ]]∗ ∗
 /w2 ]([[[e1 ]] /w1 ]

(let (w1 , w2 ) = u in f ) ([(e1 , e2 )/u]f ))

[w/u]e ≡ rename u to w in e
8
[f /u]e
(let w = u0 · e0 in f )
>
>
if u not free in e
<
[ ]e ≡
u >
> let w = u0 · e0 in [f /u]e
otherwise
:
8
[f /u]e
(let (w1 , w2 ) = u0 in f )
>
>
if u not free in e
<
[ ]e ≡
u > let (w1 , w2 ) = u0 in [f /u]e
>
otherwise
:

[(void w0 )/u] 0
≡ void w
(let w = u · e in f )
[(void w0 )/u] 0
≡ void w
(let (w1 , w2 ) = u in f )
[(void w)/u](void u) ≡ void w

M if u not free in M
[(void w)/u]M ≡
void w otherwise

If e = (λu0 ∈ τ 0 .e0 )
unit, or (e1 , e2 ), then
[e/u]M ≡ M

u 6= w, [e/u]w ≡ w
[e/u]unit ≡ unit
u 6= w, [e/u](void w) ≡ void w
0 0 0 0 0 0
[e/u](λu ∈ τ .e ) ≡ λu ∈ [e/u]τ .([e/u]e )
u 6= u0 , [e/u] 0
let w = u · ([e/u]e ) 0

(let w = u0 · e in f )
0 in ([e/u]f )
[e/u](e1 , e2 ) ≡ ([e/u]e1 , [e/u]e2 )
u 6= u0 , [e/u] let (w1 , w2 ) = u0

(let (w1 , w2 ) = u0 in f ) in ([e/u]f )

9
A weakened context Ω0 of Ω refers to an extension of Ω by new assump-
tions. Formally, we write Ω ≤ Ω0 .

Lemma 2.8 (Weakening) Let Ω ≤ Ω0 . If Ω ` e ∈ σ then Ω0 ` e ∈ σ.

Proof: By induction on typing judgment. 

Lemma 2.9 (Redundant Let)

• If Ω ` let w = u · e in f ∈ % and neither u nor w occur free in f , then


Ω`f ∈%

• If Ω ` let (w1 , w2 ) = u in f ∈ % and neither u nor w occur free in f ,


then Ω ` f ∈ %

Proof: By Induction. 

Lemma 2.10 (Redundant Term)


If u is neither free in e nor Ω2 , and Ω1 , u ∈ τ, Ω2 ` e ∈ σ, then Ω1 , Ω2 ` e ∈
σ

Proof: By Induction. 

Lemma 2.11 (Not Undefined Property)


If [e/u]σ is defined and [f /w]σ is also defined, then [e/u]([f /w]σ) is also
defined.

Proof: Trivial. 

Lemma 2.12 (Redundant Substitution on τ )

• If u is not free in τ , then [e/u]τ = τ

• If Ω ` τ wff and (u ∈ τ ) ∈ Ω and τ 6= hAi, then [e/u]τ = τ

• If e 6= M and [e/u]τ is well-formed, then [e/u]τ = τ (or equivalently


u does not occur free in τ ).

Proof: Trivial. The second and third case appeals to the first since well-
formed types cannot have variables of non-hAi type occur free. 

10
Lemma 2.13 (Substitution Distributive Property)
0
[e/u]([e0 /u0 ]τ ) = [ [e/u]e
u0 ]([e/u]τ )

Proof: (Note that the definition of substitution on expressions is given in


the beginning of this section, Section 2.3).
Therefore, If u0 is not free in τ , then it follows from Redundant Sub
Lemma (Lemma 2.12). Therefore, we now assume that u0 occurs free in τ .
which also means that e0 must be of the form M by our definition of substi-
tution.
We first assert that it also holds that if u is not free in f , then [e/u]f = f
We now proceed by induction on τ

0
Case: [e/u]([e0 /u0 ](Πw ∈ τ .σ)) = [ [e/u]e
u0 ]([e/u](Πw ∈ τ .σ))

[e/u]([e0 /u0 ](Πw ∈ τ .σ))


= Πw ∈ ([e/u]([e0 /u0 ]τ )) .(([e/u]([e0 /u0 ]σ))) by Def.
0 0
= Πw ∈ ([ [e/u]e
u 0 ]([e/u]τ )) .([ [e/u]e
u 0 ]([e/u]σ)) by IH
[e/u]e0
= [ u0 ]([e/u](Πw ∈ τ .σ)) by Def.

0
Case: [e/u]([e0 /u0 ](Σw ∈ τ .σ)) = [ [e/u]e
u0 ]([e/u](Σw ∈ τ .σ))

Same As Previous.
0
Case: [e/u]([e0 /u0 ]>) = [ [e/u]e
u0 ]([e/u]>)

Both sides equal to > by definition

0
Case: [e/u]([e0 /u0 ]⊥) = [ [e/u]e
u0 ]([e/u]⊥)

Both sides equal to ⊥ by definition

11
0
Case: [e/u]([e0 /u0 ]hAi) = [ [e/u]e
u0 ]([e/u]hAi)

e0 = M since assuming u0 free in hAi


[e/u]([M/u0 ]hAi)
= [e/u]h[M/u0 ]LF Ai by Def.

Subcase: [e/u]h[M/u0 ]LF Ai = h[M/u0 ]LF Ai


So u is neither free in M nor A
[ [e/u]M
u0 ]([e/u]hAi)
= [M/u0 ]([e/u]hAi) since u free in M
= [M/u0 ]hAi since u free in A
= h[M/u0 ]LF Ai by Definition

Subcase: e = N ,
[e/u]h[M/u0 ]LF Ai = h[N/u]LF ([M/u0 ]LF A)i
[ [N/u]M
u0 ]([N/u]hAi)
= [([N/u]LF M )/u0 ]([N/u]hAi) by Def.
= [([N/u]LF M )/u0 ]h[N/u]LF Ai by Def.
= h[([N/u]LF M )/u0 ]LF ([N/u]LF A)i by Def.
= h[N/u]LF ([M/u0 ]LF A)i by Distributivity of LF

12
2.4 Cut Admissibility Proof
Theorem 2.14 (Admissibility of cut) If D :: Ω1 ` e ∈ τ and E :: Ω1 , u ∈
τ, Ω2 ` f ∈ σ and [e/u]Ω2 is defined and [e/u]σ is defined, then Ω1 , [e/u]Ω2 `
[e/u]f ∈ [e/u]σ for some proof term [e/u]f .
Note that this lemma defines [e/u]f , i.e. substitution on terms of LhiΠ , but
we presented the results earlier, Section 2.3.

Proof: By induction on the cut formula τ , and simultaneously over deriva-


tions D and E.

First we handle the essential conversions.

Case: D = Ω1 ` e ∈ τ
(u ∈ τ ) in (Ω1 , u ∈ τ, Ω2 )
E= ax
Ω1 , u ∈ τ, Ω2 ` u ∈ τ

[e/u]Ω2 is defined. by Assumption


[e/u]τ is defined. by Assumption
Ω1 , ≤ Ω1 , [e/u]Ω2 by Definition
Ω1 , [e/u]Ω2 ` e ∈ τ by Weakening (Lemma 2.8)
Ω1 , [e/u]Ω2 ` e ∈ [e/u]τ
By Redundant Sub.,
Since u not free in τ
(Lemma 2.12)

13
D1 :: Ω1 , u0 ∈ τ ` e0 ∈ σ
Case: D = ΠR,
Ω1 ` λu0 ∈ τ .e0 ∈ Πu0 ∈ τ .σ
E1 :: Ω1 , u ∈ (Πu0 ∈ τ .σ), Ω2 ` e ∈ τ
E2 :: Ω1 , u ∈ (Πu0 ∈ τ .σ), Ω2 , w ∈ [e/u0 ]σ ` f ∈ %
E= ΠL
Ω1 , u ∈ (Πu0 ∈ τ .σ), Ω2 ` let w = u · e in f ∈ %
0 0
[ λu ∈τ
u
.e
]Ω2 is defined. by Assumption
λu0 ∈τ .e0
[ u ]% is defined. by Assumption
0 .e0 0 .e0
E10 :: Ω1 , [ λu ∈τ
u ]Ω2 ` [ λu ∈τ
u ]e ∈ τ
by IH on D and E1 and
Redundant Sub. Prop. (Lemma 2.12)
0 .e0
E20 :: Ω1 , [ λu ∈τ ]Ω , w ∈ [e/u 0 ]σ ` [ λu0 ∈τ .e0 ]f ∈ %
u 2 u
by IH on D and E2 and
Redundant Sub. Prop. (Lemma 2.12)
0 .e0
Ω1 , u0 ∈ τ ≤ Ω1 , [ λu ∈τ u ]Ω2 , u0 ∈ τ by Definition
λu0 ∈τ .e0
0
D1 :: Ω1 , [ u ]Ω2 , u ∈ τ ` e0 ∈ σ0

by Weakening (Lemma 2.8) on D1


0 ∈τ .e0
[ λu ]e 0 0
[ u
u0 ]σ = [ λu ∈τ
u
.e
]([e/u0 ]σ) = [e/u0 ]σ
by Sub. Prop. Distribute and Redundant
(Lemmas 2.13 and 2.12)
0 ∈τ .e0
0 0 [ λu ]e
D100 :: Ω1 , [ λu ∈τ
u
.e
]Ω2 ` [ u
u0 ]e0 ∈ [e/u0 ]σ
by IH on E10 and D10
0 .e0 ]e
[ λu ∈τ
[ u
u0
]e0
[ w ]% = %
by Redundant Sub., since w not free in % (Lemma 2.12)
0 .e0 ]e
[ λu ∈τ
0 .e0 [ u ]e0 0 0
F :: Ω1 , [ λu ∈τ
u ]Ω2 `[ u0
w ]([ λu ∈τ
u
.e
]f ) ∈ %
by IH on D100 and E20
0 .e0 ]e
[ λu ∈τ
0 .e0 [ u ]e0 0 0 0 0
Ω1 , [ λu ∈τ
u ]Ω2 `[ u0
w ]([ λu ∈τ
u
.e
]f ) ∈ [ λu ∈τ
u
.e
]%
by Redundant Sub. (Lemma 2.12)

14
[Ω1 ]LF ` M : A
Case: D = hiR
Ω1 ` M ∈ hAi
E1 :: [(Ω1 , u ∈ hAi, Ω2 )]LF ` N : B
E= hiR
Ω1 , u ∈ hAi, Ω2 ` N ∈ hBi

[M/u]Ω2 is defined. by Assumption (or by Def. of Sub)


[M/u]hBi is defined. by Assumption (or by Def. of Sub)
E10 :: [Ω1 ]LF , u : A, [Ω2 ]LF ` N : B
by Property of [ ]LF on E1
F :: [Ω1 ]LF , [M/u]LF [Ω2 ]LF ` [M/u]LF N : [M/u]LF B
by LF Substitution
F 0 :: [(Ω1 , [M/u]LF Ω2 )]LF ` [M/u]LF N : [M/u]LF B
by Property of [ ]LF on F
Ω1 , [M/u]Ω2 ` [M/u]LF N ∈ [M/u]hBi
by hiR and Definition of Sub.

15
D1 D2
Ω1 ` e1 ∈ τ Ω1 ` e2 ∈ [e1 /u0 ]σ
Case: D = ΣR
Ω ` (e1 , e2 ) ∈ Σu0 ∈ τ .σ
Ω1 , u ∈ (Σu0 ∈ τ .σ), Ω2 ,
E1 :: w1 ∈ τ, w2 ∈ [w1 /u0 ]σ ` f ∈ %
E= ΣL
Ω1 , u ∈ (Σu0 ∈ τ .σ), Ω2 ` let (w1 , w2 ) = u in f ∈ %

[(e1 , e2 )/u]Ω2 is defined. by Assumption


[(e1 , e2 )/u]% is defined. by Assumption
F1 :: Ω1 , [(e1 , e2 )/u]Ω2 , w1 ∈ τ, w2 ∈ [w1 /u0 ]σ
` [(e1 , e2 )/u]f ∈ %
by IH on D and E1 and
Redundant Sub. Prop. (Lemma 2.12)
D20 :: Ω1 , [(e1 , e2 )/u]Ω2 ` e2 ∈ [e1 /u0 ]σ
by Weakening (Lemma 2.8)
[e1 /w1 ]% = %
by Redundant Sub., since w1 not free in % (Lemma 2.12)
[e1 /w1 ]([w1 /u0 ]σ) = [e1 /u0 ]σ
By Prop. of Sub., Distributivity and
Redundancy (on w1 ) (Lemmas 2.13 and 2.12)
F2 :: Ω1 , [(e1 , e2 )/u]Ω2 , w2 ∈ [e1 /u0 ]σ
` [e1 /w1 ]([(e1 , e2 )/u]f ) ∈ %
by IH on D1 and F1
[e2 /w2 ]% = %
by Redundant Sub., since w2 not free in % (Lemma 2.12)
Ω1 , [(e1 , e2 )/u]Ω2
` [e2 /w2 ]([e1 /w1 ]([(e1 , e2 )/u]f )) ∈ %
by IH on D20 and F2
Ω1 , [(e1 , e2 )/u]Ω2
` [e2 /w2 ]([e1 /w1 ]([(e1 , e2 )/u]f ))
∈ [(e1 , e2 )/u]% by Redundant Sub (Lemma 2.12)

16
Now we handle commutative conversion on the left.
(w ∈ τ ) ∈ Ω1
Case: D = ax E = Ω1 , u ∈ τ, Ω2 ` e ∈ σ
Ω1 ` w ∈ τ
[w/u]Ω2 is defined. by Assumption
[w/u]σ is defined. by Assumption
Ω1 , [w/u]Ω2 ` rename u to w in e ∈ [w/u]σ
by variable renaming

Case:
D0 :: (u0 ∈ (Πu00 ∈ τ .σ)) ∈ Ω1
D1 :: Ω1 ` e0 ∈ τ
D2 :: Ω1 , w ∈ [e0 /u00 ]σ ` f ∈ %
D= ΠL
Ω1 ` let w = u0 · e0 in f ∈ %
E = Ω1 , u ∈ %, Ω2 ` e ∈ %0

[(let w = u0 · e0 in f )/u]Ω2 is defined. by Assumption


[(let w = u0 · e0 in f )/u]%0 is defined. by Assumption
0 00
F0 :: (u ∈ (Πu ∈ τ .σ))
∈ Ω1 , [(let w = u0 · e0 in f )/u]Ω2 by D0
F1 :: Ω1 , [(let w = u0 · e0 in f )/u]Ω2 ` e0 ∈ τ
by Weakening (Lemma 2.8) on D1
E 0 :: Ω1 , w ∈ [e0 /u00 ]σ, u ∈ %, Ω2 ` e ∈ %0
by Weakening (Lemma 2.8) on E
Ω1 , w ∈ [e0 /u00 ]σ, [(let w = u0 · e0 in f )/u]Ω2
` [f /u]e
∈ [(let w = u0 · e0 in f )/u]%0 by IH on D2 and E 0
0 0 0
Ω1 , [(let w = u · e in f )/u]Ω2 , w ∈ [e /u ]σ 00

` [f /u]e by Context Reordering


∈ [(let w = u0 · e0 in f )/u]%0 since w not free in Ω2
Ω1 , [(let w = u0 · e0 in f )/u]Ω2
` let w = u0 · e0 in [f /u]e
∈ [(let w = u0 · e0 in f )/u]%0 by ΠL

If u does not occur free in e, then


Ω1 , [(let w = u0 · e0 in f )/u]Ω2
` [f /u]e
∈ [(let w = u0 · e0 in f )/u]%0
by Redundant Let Lemma 2.9

17
Case:
D0 :: (u0 ∈ (Σu00 ∈ τ .σ)) ∈ Ω1
D1 :: Ω1 , w1 ∈ τ, w2 ∈ [w1 /u00 ]σ ` f ∈ %
D= ΣL
Ω1 ` let (w1 , w2 ) = u0 in f ∈ %
E = Ω1 , u ∈ %, Ω2 ` e ∈ %0

[(let (w1 , w2 ) = u0 in f )/u]Ω2 is defined.


by Assumption
[(let (w1 , w2 ) = u0 in f )/u]%0 is defined.
by Assumption
F0 :: (u0 ∈ (Σu00 ∈ τ .σ))
∈ Ω1 , [(let (w1 , w2 ) = u0 in f )/u]Ω2 by D0
E :: Ω1 , w1 ∈ τ, w2 ∈ [w1 /u00 ]σ, u ∈ %, Ω2 ` e ∈ %0
0

by Weakening (Lemma 2.8) on E


Ω1 , w1 ∈ τ, w2 ∈ [w1 /u ]σ,00

[(let (w1 , w2 ) = u0 in f )/u]Ω2


` [f /u]e
∈ [(let (w1 , w2 ) = u0 in f )/u]%0
by IH on D1 and E 0
Ω1 , [(let (w1 , w2 ) = u0 in f )/u]Ω2 ,
w1 ∈ τ, w2 ∈ [w1 /u00 ]σ
` [f /u]e
∈ [(let (w1 , w2 ) = u0 in f )/u]%0
by Context Reordering
since w1 and w2 are not free in Ω2
Ω1 , [(let (w1 , w2 ) = u0 in f )/u]Ω2
` let (w1 , w2 ) = u0 in [f /u]e
∈ [(let (w1 , w2 ) = u0 in f )/u]%0 by ΣL

If u does not occur free in e, then


Ω1 , [(let (w1 , w2 ) = u0 in f )/u]Ω2
` [f /u]e
∈ [(let (w1 , w2 ) = u0 in f )/u]%0
by Redundant Let Lemma 2.9

18
Case:
(w0 ∈ ⊥) ∈ Ω1
D= ⊥L
Ω1 ` void w0 ∈ (Πu0 ∈ τ .σ)
E1 :: Ω1 , u ∈ (Πu0 ∈ τ .σ), Ω2 ` e ∈ τ
E2 :: Ω1 , u ∈ (Πu0 ∈ τ .σ), Ω2 , w ∈ [e/u]σ ` f ∈ %
E= ΠL
Ω1 , u ∈ (Πu0 ∈ τ .σ), Ω2 ` let w = u · e in f ∈ %

[(void w0 )/u]Ω2 is defined. by Assumption


0
[(void w )/u]% is defined. by Assumption
[(void w0 )/u]Ω2 = Ω2 by Above and Def. of Sub.
[(void w0 )/u]% = % by Above and Def. of Sub.
Ω1 , Ω2 ` void w0 ∈ % by ⊥L
Ω1 , [(void w0 )/u]Ω2 ` void w0 ∈ [(void w0 )/u]% by Above

Case:
(w0 ∈ ⊥) ∈ Ω1
D= ⊥L
Ω1 ` void w0 ∈ (Σu0 ∈ τ .σ)
Ω1 , u ∈ (Σu0 ∈ τ .σ), Ω2 ,
E1 :: w1 ∈ τ, w2 ∈ [w1 /u0 ]σ ` f ∈ %
E= ΣL
Ω1 , u ∈ (Σu0 ∈ τ .σ), Ω2 ` let (w1 , w2 ) = u · e in f ∈ %

[(void w0 )/u]Ω2 is defined. by Assumption


0
[(void w )/u]% is defined. by Assumption
[(void w0 )/u]Ω2 = Ω2 by Above and Def. of Sub.
[(void w0 )/u]% = % by Above and Def. of Sub.
0
Ω1 , Ω2 ` void w ∈ % by ⊥L
Ω1 , [(void w0 )/u]Ω2 ` void w0 ∈ [(void w0 )/u]% by Above

19
Case:
(w ∈ ⊥) ∈ Ω1
D= ⊥L
Ω1 ` void w ∈ ⊥
E = Ω1 , u ∈ ⊥, Ω2 ` (void u) ∈ σ

[(void w)/u]Ω2 is defined. by Assumption


[(void w)/u]σ is defined. by Assumption
Ω1 , [(void w)/u]Ω2 ` void w ∈ σ by ⊥L
Ω1 , [(void w)/u]Ω2 ` void w ∈ [(void w)/u]σ by Above

Case:
(w ∈ ⊥) ∈ Ω1
D= ⊥L
Ω1 ` void w ∈ τ
E = Ω1 , u ∈ τ, Ω2 ` M ∈ hAi

[(void w)/u]Ω2 is defined. by Assumption


[(void w)/u]hAi is defined. by Assumption
[(void w)/u]Ω2 = Ω2 by Inversion on Def. of Sub.
and Above
u does not occur free in Ω2 by Above
[(void w)/u]hAi = hAi by Inversion on Def. of Sub.
and Above
Ω1 , Ω2 ` void w ∈ hAi by ⊥L
Ω1 , [(void w)/u]Ω2 ` void w ∈ [(void w)/u]hAi by Above

If u does not occur free in M , then


Ω1 , Ω2 ` M ∈ hAi by Redundant Term 2.10
Ω1 , [(void w)/u]Ω2 ` M ∈ [(void w)/u]hAi by Above

20
Now we handle commutative conversion cases on the right.

Case: D = Ω1 ` e ∈ τ
(w ∈ σ) in (Ω1 , u ∈ τ, Ω2 )
E= ax, where u 6= w
Ω1 , u ∈ τ, Ω2 ` w ∈ σ

[e/u]Ω2 is defined. by Assumption


[e/u]σ is defined. by Assumption
(w ∈ [e/u]σ) in (Ω1 , [e/u]Ω2 ) since u 6= w and Prop. of Sub.
Ω1 , [e/u]Ω2 ` w ∈ [e/u]σ by ax

Case: D = Ω1 ` e ∈ τ

E= >R
Ω1 , u ∈ τ, Ω2 ` unit ∈ >

[e/u]Ω2 is defined. by Assumption


Ω1 , [e/u]Ω2 ` unit ∈ > by >R
Ω1 , [e/u]Ω2 ` unit ∈ [e/u]> by Definition of Sub.

Case: D = Ω1 ` e ∈ τ
(w ∈ ⊥) ∈ (Ω1 , u ∈ τ, Ω2 )
E= ⊥L, where u 6= w
Ω1 , u ∈ τ, Ω2 ` void w ∈ σ

[e/u]Ω2 is defined. by Assumption


[e/u]σ is defined. by Assumption
(w ∈ ⊥) ∈ (Ω1 , [e/u]Ω2 ) since u 6= w and Prop. of Sub.
Ω1 , [e/u]Ω2 ` void w ∈ [e/u]σ by ⊥L

21
Case: D = Ω1 ` e ∈ τ
E1 :: Ω1 , u ∈ τ, Ω2 , u0 ∈ τ 0 ` e0 ∈ σ
E= ΠR
Ω1 , u ∈ τ, Ω2 ` λu0 ∈ τ 0 .e0 ∈ (Πu00 ∈ τ 0 .σ)

[e/u]Ω2 is defined. by Assumption


[e/u](Πu00 ∈ τ 0 .σ)) is defined. by Assumption
[e/u](Πu00 ∈ τ 0 .σ) = Πu00 ∈ [e/u]τ 0 .[e/u]σ
by Definition of Sub.
Ω1 , [e/u]Ω2 , u0 ∈ [e/u]τ 0 ` [e/u]e0 ∈ [e/u]σ
by IH on D and E1
Ω1 , [e/u]Ω2
` λu0 ∈ [e/u]τ 0 .([e/u]e0 ) ∈ Πu00 ∈ [e/u]τ 0 .[e/u]σ
by ΠR
Ω1 , [e/u]Ω2
` λu0 ∈ [e/u]τ 0 .([e/u]e0 ) ∈ [e/u](Πu00 ∈ τ 0 .σ)
by Above

22
Case: D = Ω1 ` e ∈ τ
u 6= u0
E0 :: (u0 ∈ (Πu00 ∈ τ 0 .σ 0 )) ∈ (Ω1 , u ∈ τ, Ω2 )
E1 :: Ω1 , u ∈ τ, Ω2 ` e0 ∈ τ 0
E2 :: Ω1 , u ∈ τ, Ω2 , w ∈ [e0 /u00 ]σ 0 ` f ∈ %
E= ΠL
Ω1 , u ∈ τ, Ω2 ` let w = u0 · e0 in f ∈ %

[e/u]Ω2 is defined. by Assumption


[e/u]% is defined. by Assumption
F0 :: (u0 ∈ (Πu00 ∈ [e/u]τ 0 .[e/u]σ 0 )) ∈ (Ω1 , [e/u]Ω2 )
since u 6= u0 and Def. of Sub.
0
F1 :: Ω1 , [e/u]Ω2 ` [e/u]e ∈ [e/u]τ 0

by IH on D and E1
[e/u]([e0 /u00 ]σ 0 ) is defined.
by Not Undefined Prop. (Lemma 2.11)
[e/u]([e /u ]σ ) = [([e/u]e )/u ]([e/u]σ 0 )
0 00 0 0 00

by Sub. Distribute Prop. (Lemma 2.13)


F2 :: Ω1 , [e/u]Ω2 , w ∈ [([e/u]e )/u00 ]([e/u]σ 0 )
0

` [e/u]f ∈ [e/u]%
by IH on D and E2
0 0
Ω1 , [e/u]Ω2 ` let w = u · ([e/u]e ) in ([e/u]f ) ∈ [e/u]%
by ΠL

23
Case: D = Ω1 ` e ∈ τ
E1 :: Ω1 , u ∈ τ, Ω2 ` e1 ∈ σ1
E2 :: Ω1 , u ∈ τ, Ω2 , ` e2 ∈ [e1 /u0 ]σ2
E= ΣR
Ω1 , u ∈ τ, Ω2 ` (e1 , e2 ) ∈ Σu0 ∈ σ1 .σ2

[e/u]Ω2 is defined. by Assumption


[e/u](Σu0 ∈ σ1 .σ2 ) is defined. by Assumption
0 0
[e/u](Σu ∈ σ1 .σ2 ) = Σu ∈ [e/u]σ1 .[e/u]σ2
by Above and Def. of Sub.
F1 :: Ω1 , [e/u]Ω2 ` [e/u]e1 ∈ [e/u]σ1
by IH on D and E1
[e/u]([e1 /u0 ]σ2 ) is defined.
by Not Undefined Prop. (Lemma 2.11)
[e/u]([e1 /u0 ]σ2 ) = [([e/u]e1 )/u0 ]([e/u]σ2 )
by Sub. Distribute Prop. (Lemma 2.13)
F2 :: Ω1 , [e/u]Ω2 ` [e/u]e2 ∈ [([e/u]e1 )/u0 ]([e/u]σ2 )
by IH on D and E2
0
Ω1 , [e/u]Ω2 ` ([e/u]e1 , [e/u]e2 ) ∈ Σu ∈ [e/u]σ1 .[e/u]σ2
by ΣR
Ω1 , [e/u]Ω2 ` ([e/u]e1 , [e/u]e2 ) ∈ [e/u](Σu0 ∈ σ1 .σ2 )
by Above

24
Case: D = Ω1 ` e ∈ τ
u 6= u0
E0 :: (u0 ∈ (Σu00 ∈ τ 0 .σ 0 )) ∈ (Ω1 , u ∈ τ, Ω2 )
E1 :: Ω1 , u ∈ τ, Ω2 , w1 ∈ τ 0 , w2 ∈ [w1 /u00 ]σ 0 ` f ∈ %
E= ΣL
Ω1 , u ∈ τ, Ω2 ` let (w1 , w2 ) = u0 in f ∈ %

[e/u]Ω2 is defined. by Assumption


[e/u]% is defined. by Assumption
F0 :: (u0 ∈ (Σu00 ∈ [e/u]τ 0 .[e/u]σ 0 )) ∈ (Ω1 , [e/u]Ω2 )
since u 6= u0 and Def. of Sub.
00 0
[e/u]([w1 /u ]σ ) is defined.
by Not Undefined Prop. (Lemma 2.11)
[e/u]([w1 /u ]σ ) = [w1 /u ]([e/u]σ 0 )
00 0 00

by Def. of Sub. and Sub. Distribute Prop. (Lemma 2.13)


F1 :: Ω1 , [e/u]Ω2 , w1 ∈ [e/u]τ 0 , w2 ∈ [w1 /u00 ][e/u]σ 0
` [e/u]f ∈ [e/u]%
by IH on D and E1
0
Ω1 , [e/u]Ω2 ` let (w1 , w2 ) = u in ([e/u]f ) ∈ [e/u]%
by ΣL

25
2.5 Result
Thus we add the cut-rule to LhiΠ and obtain a logic with cut called LhiΠcut

Theorem 2.15 (Cut-Elimination) Let Ω ` e ∈ τ be a derivation in


LhiΠcut . Then there exists an e0 such that Ω ` e0 ∈ τ in LhiΠ .

It is easy to see that D :: · ` e ∈ ⊥ cannot be a valid derivation in


LhiΠcut . If it were, there is a valid derivation E :: · ` e0 ∈ ⊥ in LhiΠ , which
is impossible by inspection of the right rules.

Corollary 2.16 (Soundness) The logics LhiΠ and LhiΠcut are sound.

2.6 Curry-Howard Isomorphism, λhiΠ


Our sequent-calculus lends itself for an operational interpretation where the
cut-rule is the one that triggers evaluation. Hence cut-free derivations play
the role of normal forms, or values.
The operational behavior of the λhiΠ -calculus is footed on how substi-
tutions are pushed into the proof terms, which corresponds directly to the
process of cut-elimination. We therefore interpret the proof of the admis-
sibility of cut (Theorem 2.14) as equivalences on proof terms. A detailed
table can be found in Section 2.3 but we repeat some of the interesting
equivalences below.


e if u = w
[e/u]w ≡
w otherwise
0 ∈τ .e0
[(λu0 ∈ τ .e0 )/u] [ λu ]e
[ u
u0 ]e0 λu0 ∈ τ .e0
(let w = u · e in f ) ≡ [ ]([ ]f )
w u
(let w = u0 · e0 in f )
[ ]e ≡ let w = u0 · e0 in [f /u]e
u
[(e1 , e2 )/u] [e2 /w2 ]([e1 /w1 ]

(let (w1 , w2 ) = u in f ) ([(e1 , e2 )/u]f ))
[M/u]N ≡ [M/u]LF N

At first glance this definition of substitution looks needlessly complicated.


However, it is simply because we are using a sequent-calculus instead of
natural deduction.

Definition 2.17 (Values) The following syntactic category denotes all val-
ues of the λhiΠ -calculus: v ::=| λu ∈ τ .e | unit | M | (v1 , v2 ).

26
With this computational view of LhiΠ we can show that for every ex-
pression e can always be reduced to a value v. We define reduction as the
reflexive, transitive closure of ≡. This property is called strong normaliza-
tion.

Theorem 2.18 (Strong Normalization) If · ` e ∈ τ then e reduces to a


value v.

Therefore we see that we can interpret the judgments of LhiΠ in a compu-


tational manner. We will use λhiΠ when we refer to the system computation-
ally. The relationship between a logic and its corresponding computational
behavior is also called the Curry-Howard isomorphism.
Finally, we point out that although substitution on types is not defined
everywhere, it is total for substitutions of values.

Theorem 2.19 (Completeness of Substitution on Values)


[v/u]τ is always defined.

Proof: By analysis of the definition of substitution. 

3 Past-Time Temporal Logic


We now present our temporal meta logic to reason about derivations of LhiΠ
at different times. Here we utilize a past-time modal operator over the
types τ of LhiΠ .
κ, α ::= κ | τ
We write Φ ` ` κ for the central derivability judgment and adopt the
shorthand i τ to indicate there are i leading ’s to τ . Our context, Φ ::=
· | Φ, u ∈ κ is simply a collection of κ’s, . Time travel is defined with respect
to adding and removing ’s to all hypothesis in Φ. Namely, Φ− changes our
point-of-reference one step to the past by removing anything in the present
(without a leading ) and removing a leading from the remaining.

Definition 3.1 (MovePast)



 · if Φ = ·
 0 −
if Φ = Φ0 , u ∈ κ

Φ , u ∈ κ
Φ− = −

 Φ0 if Φ = Φ0 , u ∈ τ

27
Similarly, we define Φ+ to take us one step to the future by adding a to
everything in Φ. Finally, we also define a thinning operation [Φ] that strips
all ’s from Φ to give us a context of the form Ω.

Definition 3.2 (Temporal Thinning)



 · if Φ = ·
[Φ] = [Φ0 ], u ∈ τ if Φ = Φ0 , u ∈ i τ

It is important to discuss why we create a meta logic for LhiΠ instead


of just adding a modal operator directly to LhiΠ . The former uses time
to reason over derivations whilst the latter would use time to reason over
propositions. For the use of Higher-Order Abstract Syntax, we need to
reason about entire derivations to argue that parameters do not escape their
scope as will be shown in Section 4. The meaning of τ is that τ is derivable
under the logic LhiΠ without making use of any hypothesis that does not
exist in the past.
Alternatively, the intrinsic behavior behind our logic is that we desire
that τ means that τ can be shown in the past with just the tools of the
past. It should be no different concluding τ in the present or going to the
past and proving τ . For instance if τ is a proposition ascertaining culpability
of a past crime using DNA technology of today, then our logic will disallow
proving τ . This inherent strengthening property is the essential necessary
component to our logic.
We will call this logic LhiΠ (or λhiΠ as a calculus) and it comprises
just two judgments.

Φ− `
`e∈κ [Φ] ` e ∈ τ
R bridge
Φ`
` prev e ∈ κ Φ `` e ∈ τ

This meta logic is very minimal (although it will be extended shortly)


and is notably missing constructs for abstraction and application. However,
we are designing this logic to reason about the derivability of LhiΠ and the
study of functions at this meta-meta-level are left for future research. The
R rule allows us to travel back in time and the bridge rule ties LhiΠ into
our system.

Theorem 3.3 (Future)


` e ∈ κ, then there exists an e0 such that Φ ` e0 ∈ κ.
If Φ+ `

28
Proof: By induction on the typing judgment of LhiΠ and LhiΠ . 

Thus, the following rule is admissible, which also serves as the elimination
rule for .
Φ+ `` e ∈ κ
future
Φ `` next e ∈ κ
We first need to show that if κ is derivable in the past then it is also
derivable now. We call this shifting and due to our design we can also show
that the proof-term stays the same. Since we are dealing with dependent-
types, this property proves to be crucial.

Lemma 3.4 (Shifting)

• If Φ− ` e ∈ κ then Φ `` e ∈ κ.

• If Φ ` previ e ∈ i τ then [Φ] ` e ∈ τ .

Proof: By induction on typing judgment of LhiΠ and LhiΠ . 

Recall that since we are dealing with dependent-types we need to extend


our definition of substitution for κ.

[(prev e)/u]( κ) = ([e/u]κ)


[(prev e)/u]τ = [e/u]τ
[e/u]( κ), u not free in κ = κ
None of the above match, [e/u]κ = undefined

We also need to extend our definition of well-formedness with


Φ− ` κ wff
wffR
Ω ` κ wff

Before proving the admissibility of cut, we update Weakening and our


Redundant Substitution lemmas.
A weakened context Φ0 of Φ refers to an extension of Φ by new assump-
tions. Formally, we write Φ ≤ Φ0 .

Lemma 3.5 (Weakening) Let Φ ≤ Φ0 . If Φ ` e ∈ κ then Φ0 ` e ∈ κ.

Proof: By induction on typing judgment. 

Lemma 3.6 (Redundant Substitution on κ)

29
• If u is not free in κ, then [e/u]κ = κ

• If Ω ` κ wff and (u ∈ κ) ∈ Ω and κ 6= k hAi, then [e/u]κ = κ

• If e 6= prevk M and [e/u]κ is well-formed, then [e/u]κ = κ (or equiv-


alently u does not occur free in κ).

Proof: Trivial. The second and third case appeals to the first since well-
formed types cannot have variables of non- k hAi type occur free. 

Theorem 3.7 (Admissibility of cutT) If D :: Φ1 ` e ∈ κ and E ::


Φ1 , u ∈ κ, Φ2 ` κ0 wff and [e/u]Φ2 is defined and [e/u]κ0 is defined, then
Φ1 , [e/u]Φ2 ` [e/u]κ0 wff.

Proof: This proof goes by induction over derivation E utilizing the defini-
tion of [e/u]κ0 . 

Finally we show that the following cut rule is admissible:

[e/u]Φ2 is defined [e/u]κ0 is defined


Φ1 `` e ∈ κ Φ1 , u ∈ κ, Φ2 ` f ∈ κ0
cut
Φ1 , [e/u]Φ2 `` [e/u]f ∈ [e/u]κ0

30
Theorem 3.8 (Admissibility of cut) If D :: Φ1 `` e ∈ κ and
` f ∈ κ0 and [e/u]Φ2 is defined and [e/u]κ0 is defined, then
E :: Φ1 , κ, Φ2 `
Φ1 , [e/u]Φ2 `` [e/u]f ∈ [e/u]κ0 .
Note that this lemma defines [e/u]f , i.e. substitution on terms of LhiΠ .

Proof: By induction on the cut formula κ, and simultaneously over deriva-


tions D and E.
D1 :: Φ1 − `
`e∈κ
Case: D = R
Φ1 `
` prev e ∈ κ

E1 :: (Φ1 , u ∈ κ, Φ2 )− `` f ∈ κ0
E= R
` prev f ∈ κ0
Φ1 , u ∈ κ, Φ2 `

E10 :: Φ1 − , u ∈ κ, Φ2 − `` f ∈ κ0
by Property of ( )− on E1
− −
F :: Φ1 `` [e/u]f ∈
, [e/u]Φ2 [e/u]κ0
by Induction Hypothesis on D1 and E10
0 −
F :: (Φ1 , [(prev e)/u]Φ2 ) `` [e/u]f ∈ [e/u]κ0
by Def. of Sub.
F :: Φ1 , [(prev e)/u]Φ2 `` prev ([e/u]f ) ∈ [(prev e)/u]κ0
00

by R and Def. of Sub.

D1 :: Φ1 − `
` previ e ∈ i σ
Case: D = R
` previ+1 e ∈ i+1 σ
Φ1 `

E1 :: [Φ1 , u ∈ i+1 σ, Φ2 ] ` f ∈ τ
E= bridge
Φ1 , u ∈ i+1 σ, Φ2 `` f ∈ τ

D0 :: [Φ1 ] ` e ∈ σ
by Shifting (Lemma 3.4) on D
E10 :: [Φ1 ], u ∈ σ, [Φ2 ] ` f ∈ τ
by Property of [ ] on E1
F :: [Φ1 ], [e/u][Φ2 ] ` [e/u]f ∈ [e/u]τ
by Admissibility of Cut in LhiΠ (Theorem 2.14)
0
F :: [Φ1 , [(prev i+1 e)/u]Φ2 ] ` [e/u]f ∈ [e/u]τ
by Def. of Sub.
F 00 :: Φ1 , [(previ+1 e)/u]Φ2 `` [e/u]f ∈ [(previ+1 e)/u]τ
by bridge and Def. of Sub.

31
D1 :: [Φ1 ] ` e ∈ τ
Case: D = bridge
Φ1 `
`e∈τ
E1 :: [Φ1 , u ∈ τ, Φ2 ] ` f ∈ σ
E= bridge
Φ1 , u ∈ τ, Φ2 `
`f ∈σ

E10 :: [Φ1 ], u ∈ τ, [Φ2 ] ` f ∈ σ


by Property of [ ] on E1
F :: [Φ1 ], [e/u][Φ2 ] ` [e/u]f ∈ [e/u]τ
by Admissibility of Cut in LhiΠ (Theorem 2.14)
F 0 :: [Φ1 , [e/u]Φ2 ] ` [e/u]f ∈ [e/u]τ
by Def. of Sub.
00
F :: Φ1 , [e/u]Φ2 ` ` [e/u]f ∈ [e/u]τ
by bridge

D1 :: [Φ1 ] ` e ∈ τ
Case: D = bridge
Φ1 `
`e∈τ

E1 :: (Φ1 , u ∈ τ, Φ2 )− `` f ∈ κ
E= R
Φ1 , u ∈ τ, Φ2 `
` prev f ∈ κ

E10 :: (Φ1 , Φ2 )− `
`f ∈κ
by Property of ( )− on E1
F :: Φ1 , Φ2 `
` prev f ∈ κ
by R
[e/u]Φ2 = Φ2 and [e/u]κ = κ
By Redundant Substitution Lemma (Lemma 3.6)
since u cannot occur free by well-formedness of E10
F 0 :: Φ1 , [e/u]Φ2 `
` prev f ∈ [e/u]κ
by Above

Hence, we add the admissible cut rule to the proof theory of LhiΠ and
obtain a logic we refer to as LhiΠ cut (and a calculus we refer to as λhiΠ cut ).

Corollary 3.9 (Soundness) The logics LhiΠ and LhiΠ cut are sound.

32
3.1 Operational Behavior
As we did in Section 2.6 we interpret the proof of the admissibility of cut as
equivalences on proof terms.

[(prev e)/u](prev f ) ≡ prev ([e/u]f )


f 6= prev f 0 , [(prev e)/u]f ≡ [e/u]f
0
e 6= prev e , [e/u](prev f ) ≡ prev f

Finally, we extend the definition of Values in Definition 2.17 to include


prev v.

Definition 3.10 (Values) The following syntactic category denotes all val-
ues of the λhiΠ -calculus: v ::=| λu ∈ τ .e | unit | M | (v1 , v2 ) | prev v.

3.2 Bridging bidirectionally


It is clear to see that LhiΠ can be used to reason about LhiΠ through the
bridge rule. However, inside LhiΠ it is completely unaware of LhiΠ . Since
we are reasoning about derivations this was the natural thing to do. We
have defined LhiΠ as a meta-logic for LhiΠ .
However, it is desirable from within LhiΠ to make some meta arguments.
Recall that Ω is a valid context of the form Φ and consider the following
rule.
Ω `` e ∈ τ
meta
Ω`e∈τ
` τ is a meta-level (LhiΠ ) statement that τ is derivable
Recall that Ω `
in LhiΠ in the present. Therefore, in prose this rule is stating that if LhiΠ
can show that τ is derivable in LhiΠ , then we can conclude that there exists
a proof in LhiΠ . Therefore, it is not surprising that this is an admissible
rule. Notice as well that both bridge (in LhiΠ ) and now meta (in LhiΠ ) do
not change the proof-term.

Lemma 3.11 (Admissible meta) If Ω `` e ∈ τ then Ω ` e ∈ τ

Proof: By Inversion on Ω `` e ∈ τ using bridge 

This concludes the logical motivation for this paper. The remainder is
dedicated to interpreting the corresponding λhiΠ calculus as a functional
programming language. We first add an operator for programming with

33
higher-order encodings, which is just an admissible rule. We will then sim-
plify our logic to an equivalent form called Delphin (λD ) and proceed to add
operators that facilitate case analysis and recursion. It is beyond the scope
of this paper to give a completely logical account for these new concepts.
For example, in order to still guarantee cut-elimination, we would have to
show that all cases are covered, and that the recursion always terminates.

4 Higher-Order Abstract Syntax


The temporal features of the λhiΠ -calculus are instrumental when program-
ming with higher-order abstract syntax and hypothetical judgments. When
programming with higher-order abstract syntax, one always runs into the
problem that computation somehow has to progress under a representation-
level λ-binder. There are many different views on how this can best be
achieved. For example, one may use a custom tailored iteration construct [SDP01]
or one may use an explicit ν-operator that introduces new parameters and
abstracts the result [Tah04, Sch05]. The main difficulty, particularly with
the latter technique, is to express what to do with the new parameters upon
return. To always abstract it may be too rigid because it is possible that
the result does not depend on the parameter. However, to allow the pro-
grammer to express when to abstract it is dangerously general because now
parameters are permitted to escape their scope.
The temporal properties of the λhiΠ -calculus give the programmer the
ability to express which parameters should be abstracted and when, while
simultaneously enforcing that parameters cannot escape their scope. We
can observe that if an expression evaluates to a value v of type hBi, then
anything that lies in Φ without a is invisible and can be removed without
destroying the derivability that v is a value of type hBi. This was the
critical notion behind the design of this system. This operation is also called
strengthening and it is a property of the temporal part of the calculus.

Theorem 4.1 (Strengthen)


If Φ, u ∈ τ `
` e ∈ κ, then Ω `` e ∈ κ

Proof: By induction over the typing derivation. 

Thus, the following rule is admissible.


Φ, u ∈ τ `` e ∈ κ
new
Ω `` νu ∈ τ .e ∈ κ

34
Notice that new will be used to introduce parameters into the context which
we can use to go under λ-binders.
Thus the final version of our logic, LhiΠ cut+ , is sound and defined as
follows:
Φ− ` `e∈κ [Φ] ` e ∈ τ
R bridge
Φ` ` prev e ∈ κ Φ `` e ∈ τ

Φ+ `
` e ∈ κ Φ, u ∈ τ `` e ∈ κ
future new
Φ`
` next e ∈ κ Ω `` νu ∈ τ .e ∈ κ

[e/u]Φ2 is defined [e/u]κ0 is defined


Φ1 `` e ∈ κ Φ1 , u ∈ κ, Φ2 ` f ∈ κ0
cut
Φ1 , [e/u]Φ2 `` [e/u]f ∈ [e/u]κ0
In addition, the logic we use in bridge is LhiΠcut with the admissible meta
rule.

5 Delphin
Our design has led us to a three-tiered system with an explicit bridge and
meta rule, called LhiΠ cut+ . In addition we have three contexts to reason
about. We have Γ at the bottom, Ω at its meta-level, and Φ at its meta-meta-
level. However, since both logics can communicate, we present an equivalent
simplified version so we don’t need bridge and meta and in addition get rid
of dealing with Ω. Since we are also shifting our focus to computation we
take the liberty of replacing the sequent let version of application with the
more natural version, e1 e2 .
Therefore, we present here the equivalent logic LD (or calculus λD ),
which will be the focus for the rest of this paper. Note that the purpose of
this section is twofold – it both summarizes the logical system to this point
and simplifies it into one judgment, Φ `d e ∈ κ
Types remain unchanged and are:

κ, α ::= κ | τ
τ, σ, % ::= > | ⊥ | Πu ∈ τ .σ | Σu ∈ τ .σ | hAi

Expressions are now:

e, f ::= u | unit | void e | λu ∈ τ .e | e1 e2 | prev e | next e


| (e1 , e2 ) | let (w1 , w2 ) = e in f | νu ∈ τ .e | M

35
We collapse the logics together by having the ax rule do the work of
merge in transforming the context. Note that we can interpret the ax rule
as shifting all hypothesis to the present thereby enforcing that only the
temporal rules have any access to time information, which is our desired
semantics.

(u ∈ i τ ) in Φ
ax top
Φ `d u ∈ τ Φ `d unit ∈ >

Φ, u ∈ τ `d e ∈ σ
lam
Φ `d λu ∈ τ .e ∈ Πu ∈ τ .σ

Φ `d e1 ∈ (Πu0 ∈ τ .σ) Φ `d e2 ∈ τ
app
d 0
Φ ` e1 e2 ∈ [e2 /u ]σ

Φ `d e1 ∈ τ Φ `d e2 ∈ [e1 /u]σ
pair
Φ `d (e1 , e2 ) ∈ Σu ∈ τ .σ

Φ `d e ∈ (Σw1 ∈ τ .σ) Φ, w1 ∈ τ, w2 ∈ σ `d f ∈ %
openPair
Φ `d let (w1 , w2 ) = e in f ∈ %

Φ `d e ∈ ⊥ [Φ]LF ` M : A
bot hiI
Φ `d void e ∈ σ Φ `d M ∈ hAi

Φ− `d e ∈ κ Φ+ `d e ∈ κ
past future
Φ `d prev e ∈ κ Φ `d next e ∈ κ

Φ, u ∈ τ `d e ∈ κ
new
Φ `d νu ∈ τ .e ∈ κ

It is important to note that our openPair rule which corresponds to ΣL


has kept its sequent flavor in lieu of the typical fst and snd deconstructors.
We could have chosen the latter approach but that would needlessly compli-
cate type-level substitutions. Currently, types can only depend on LF terms
and are not allowed to depend on meta-level computation. However, if we
introduce meta-level constructs of fst and snd and would like to keep them
as dependent, then snd e would have a type of the form [(fst e)/u]σ, and we
would have to allow types to handle these meta-level constructs. Now if LF

36
supported pairs, then we would just define our thinning operation to cast
it appropriately. However, LF does not support pairing. We could alterna-
tively adopt a fst and snd notation and have the thinning operation extend
the context by opening up all the pairs, but this would just be a hack and
make things needlessly more convoluted.
Substitution on types remains unchanged (only defined for LF terms)
and is as follows:

[e/u]> = >
[e/u]⊥ = ⊥
[e/u](Πu ∈ τ .σ) = Πu0 ∈ [e/u]τ .[e/u]σ
0

[e/u](Σu0 ∈ τ .σ) = Σu0 ∈ [e/u]τ .[e/u]σ


[M/u]hAi = h[M/u]LF N i
[e/u]τ, u not free in τ = τ
None of the above match, [e/u]τ = undefined

Currently LF thinning is only defined on Ω but it is easy to combine the


definition of [Φ] and [Ω]LF into [Φ]LF below.

Definition 5.1 (Thinning for Natural Deduction)



 · if Φ = ·
 0
if Φ = Φ0 , u ∈ i hAi

[Φ ]LF , u : A
[Φ]LF =

 [Φ0 ]LF if Φ = Φ0 , u ∈ τ and τ 6= i hAi

5.1 Equivalence Proof Details


First we need to prove some preliminaries.

Lemma 5.2 (DeShifting) If [Φ] `d e ∈ τ then Φ `d e ∈ τ

Proof: By Induction on [Φ] `d e ∈ τ . Note that the only interesting case is


ax where it demonstrates this property since it throws out all time informa-
tion (all ’s). 

Lemma 5.3 (Weakening) Let Φ ≤ Φ0 . If Φ `d e ∈ κ then Φ0 `d e ∈ κ.

Proof: By induction on typing judgment. 

37
In order to prove that LhiΠ cut+ is equivalent to LD we proceed by
proving this in both directions separately.

Lemma 5.4 (LhiΠ cut+ to LD )

1. If Ω ` e ∈ τ then there exists an e0 such that Ω `d e0 ∈ τ


and if e = M then e0 = M .

` e ∈ κ then there exists an e0 such that Φ `d e0 ∈ κ


2. If Φ `
and if e = previ M then e0 = previ M .

Proof: By Induction on D :: Ω ` e ∈ τ for Part 1 and by Induction on


D :: Φ `
` e ∈ κ for Part 2. Note that since the cut rules are admissible rules
from the others, we observe that for any derivation D, there exists a cut-free
derivation. Therefore, we do induction just over cut-free derivations.

Part 1: By Induction on cut-free derivations D :: Ω ` e ∈ τ .

(u ∈ τ ) in Ω
Case: D = ax
Ω`u∈τ

Ω `d u ∈ τ by ax

Case: D = >R
Ω ` unit ∈ >

Ω `d unit ∈ > by top

38
Case: D = ⊥L
Ω1 , u ∈ ⊥, Ω2 ` void u ∈ σ

Ω `d u ∈ ⊥ by ax
Ω `d void u ∈ σ by bot

D1 :: Ω, u ∈ τ ` e ∈ σ
Case: D = ΠR
Ω ` λu ∈ τ .e ∈ Πu ∈ τ .σ

Ω, u ∈ τ `d e0 ∈ σ by IH on D1
Ω `d λu ∈ τ .e0 ∈ Πu ∈ τ .σ by lam

D1 :: Ω1 , u ∈ (Πu0 ∈ τ .σ), Ω2 ` e ∈ τ
D2 :: Ω1 , u ∈ (Πu0 ∈ τ .σ), Ω2 , w ∈ [e/u0 ]σ ` f ∈ %
Case: D = ΠL
Ω1 , u ∈ (Πu0 ∈ τ .σ), Ω2 ` let w = u · e in f ∈ %

Ω1 , u ∈ (Πu0 ∈ τ .σ), Ω2 `d u ∈ Πu0 ∈ τ .σ by ax


Ω1 , u ∈ (Πu0 ∈ τ .σ), Ω2 `d e0 ∈ τ by IH on D1
Ω1 , u ∈ (Πu0 ∈ τ .σ), Ω2 `d (u e0 ) ∈ [e0 /u0 ]σ by app
If e = M then e = M 0 by IH on D1
[e0 /u0 ]σ = [e/u0 ]σ by Above and Redundant Sub.
(Lemma 2.12)
Ω1 , u ∈ (Πu0 ∈ τ .σ), Ω2 `d (u e0 ) ∈ [e/u0 ]σ by Above
Ω1 , u ∈ (Πu0 ∈ τ .σ), Ω2 , w ∈ [e/u0 ]σ `d f 0 ∈ % by IH on D2
Ω1 , u ∈ (Πu0 ∈ τ .σ), Ω2 `d λw ∈ [e/u0 ]σ .f 0 ∈ Πw ∈ [e/u0 ]σ .% by lam
[(u e0 )/w]% = % By Redundant Sub.,
Since w not free in %. (Lemma 2.12)
Ω1 , u ∈ (Πu0 ∈ τ .σ), Ω2 `d (λw ∈ [e/u0 ]σ .f 0 ) (u e0 ) ∈ % by app

39
D1 D2
Ω ` e1 ∈ τ Ω ` e2 ∈ [e1 /u]σ
Case: D = ΣR
Ω ` (e1 , e2 ) ∈ Σu ∈ τ .σ

Ω `d e01 ∈ τ by IH on D1
If e1 = M1 then e01 = M1 by IH on D1
[e01 /u]σ = [e1 /u]σ by Above and Redundant Sub.
(Lemma 2.12)
Ω `d e02 ∈ [e01 /u]σ by IH on D2
Ω `d (e01 , e02 ) ∈ Σu ∈ τ .σ by pair

D1 :: Ω1 , u ∈ (Σu0 ∈ τ .σ), Ω2 , w1 ∈ τ, w2 ∈ [w1 /u0 ]σ ` e ∈ %


Case: D = ΣL
Ω1 , u ∈ (Σu0 ∈ τ .σ), Ω2 ` let (w1 , w2 ) = u in e ∈ %

Ω1 , u ∈ (Πu0 ∈ τ .σ), Ω2 `d u ∈ Πu0 ∈ τ .σ by ax


Ω1 , u ∈ (Σu0 ∈ τ .σ), Ω2 `d u ∈ (Σu0 ∈ τ .σ) by ax
Ω1 , u ∈ (Σu0 ∈ τ .σ), Ω2 , w1 ∈ τ, w2 ∈ [w1 /u0 ]σ `d e0 ∈ % by IH on D1
Ω1 , u ∈ (Σu0 ∈ τ .σ), Ω2 `d let (w1 , w2 ) = u in e0 ∈ % by openPair

D1
[Ω]LF ` M : A
Case: D = hiR
Ω ` M ∈ hAi

Ω `d M ∈ hAi by hiI on D1

D1
Ω`
`e∈τ
Case: D = meta
Ω`e∈τ

Φ `d e0 ∈ τ
and if e = M then e0 = M . by IH on D1

40
Part 2: By Induction on cut-free derivations D :: Φ `` e ∈ κ.

D1
Φ− `
`e∈κ
Case: D = R
Φ`
` prev e ∈ κ

Φ− `d e0 ∈ κ by IH on D1
If e = previ M then e0 = previ M by IH on D1
Φ `d prev e0 ∈ κ by past
If (prev e = previ M ) then (prev e0 = previ M ) by Above

D1
[Φ] ` e ∈ τ
Case: D = bridge
Φ`
`e∈τ

[Φ] `d e0 ∈ τ by IH on D1
If e = M then e0 = M by IH on D1
Φ `d e0 ∈ τ by DeShifting (Lemma 5.2)
If e = previ M then e0 = previ M by Above

D1
Φ+ `
` e ∈ κ
Case: D = future
Φ`
` next e ∈ κ

Φ+ `d e0 ∈ κ by IH on D1
Φ `d next e0 ∈ κ by future

D1
Φ, u ∈ τ `
` e ∈ κ
Case: D = new
Ω`
` νu ∈ τ .e ∈ κ

Φ, u ∈ τ `d e0 ∈ κ by IH on D1
Φ `d νu ∈ τ .e0 ∈ κ by new

41
Lemma 5.5 (LD to LhiΠ cut+ )
If Φ `d e ∈ κ then there exists an e0 such that Φ `` e0 ∈ κ and

• if κ = τ then there exists an f such that [Φ] ` f ∈ τ .

• if e = previ M then e0 = previ M .

Proof: By Induction on D :: Φ `d e ∈ κ.

(u ∈ i τ ) in Φ
Case: D = ax
Φ `d u ∈ τ

[Φ] ` u ∈ τ by ax and Definition of [ ]


Φ``u∈τ by bridge

Case: D = top
Φ `d unit ∈ >

[Φ] ` unit ∈ > by top


Φ`` unit ∈ > by bridge

D1
Φ, u ∈ τ `d e ∈ σ
Case: D = lam
Φ `d λu ∈ τ .e ∈ Πu ∈ τ .σ

[Φ], u ∈ τ ` e0 ∈ σ by IH on D1 and Def. of [ ]


[Φ] ` λu ∈ τ .e0 ∈ Πu ∈ τ .σ by ⊃ R
Φ`` λu ∈ τ .e0 ∈ Πu ∈ τ .σ by bridge

42
D1 D2
Φ `d e1 ∈ (Πu0 ∈ τ .σ) Φ `d e2 ∈ τ
Case: D = app
Φ `d e1 e2 ∈ [e2 /u0 ]σ

[Φ] ` e01 ∈ Πu0 ∈ τ .σ by IH on D1


[Φ] ` e02 ∈ τ by IH on D2
[Φ], u ∈ (Πu0 ∈ τ .σ) ` e02 ∈ τ by Weakening (Lemma 2.8)
[Φ], u ∈ (Πu0 ∈ τ .σ) ` u ∈ Πu0 ∈ τ .σ by ax
[Φ], u ∈ (Πu0 ∈ τ .σ) ` let w = u · e02 in w ∈ [e02 /u0 ]σ by ⊃ L
[e01 /u][e02 /u0 ]σ = [e02 /u0 ]σ by Redundant Sub (Lemma 2.12)
[Φ] ` [e01 /u](let w = u · e02 in w) ∈ [e02 /u0 ]σ by cut
If e2 = M then e02 = M by IH on D2
[e02 /u0 ]σ = [e2 /u0 ]σ by Above and Redundant Sub.
(Lemma 2.12)
0 0
[Φ] ` [e1 /u](let w = u · e2 in w) ∈ [e2 /u ]σ 0 by Above
Φ` ` [e01 /u](let w = u · e02 in w) ∈ [e2 /u0 ]σ by bridge

D1 D2
Φ `d e1 ∈ τ Φ `d e2 ∈ [e1 /u]σ
Case: D = pair
Φ `d (e1 , e2 ) ∈ Σu ∈ τ .σ

[Φ] ` e01 ∈ τ by IH on D1
If e1 = M then e01 = M by IH on D1
[e01 /u]σ = [e1 /u]σ by Above and Redundant Sub.
(Lemma 2.12)
[Φ] ` e02 ∈ [e01 /u]σ by IH on D2
[Φ] ` (e01 , e02 ) ∈ Σu ∈ τ .σ by ΣR
Φ`` (e01 , e02 ) ∈ Σu ∈ τ .σ by bridge

43
D1 D2
Φ `d e ∈ (Σw1 ∈ τ .σ) Φ, w1 ∈ τ, w2 ∈ σ `d f ∈ %
Case: D = openPair
Φ `d let (w1 , w2 ) = e in f ∈ %

[Φ] ` e0 ∈ (Σw1 ∈ τ .σ) by IH on D1


[Φ], w1 ∈ τ, w2 ∈ σ ` f 0 ∈ % by IH on D2
[Φ], u ∈ (Σw1 ∈ τ .σ), w1 ∈ τ, w2 ∈ σ ` f 0 ∈ % by Weakening
(Lemma 2.8)
[Φ] ` let (w1 , w2 ) = u in f 0 ∈ % by ΣL
Φ`` let (w1 , w2 ) = u in f 0 ∈ % by bridge

D1
Φ `d e ∈ ⊥
Case: D = bot
Φ `d void e ∈ σ

[Φ] ` e0 ∈ ⊥ by IH on D1
[Φ], u ∈ ⊥ ` void u ∈ σ by ⊥L
[Φ] ` [e0 /u](void u) ∈ σ by cut
Φ`` [e0 /u](void u) ∈ σ by bridge

D1
[Φ]LF ` M : A
Case: D = hiI
Φ `d M ∈ hAi

[Φ] ` M ∈ hAi by hiR and Property of [ ]


Φ`` M ∈ hAi by bridge

D1
Φ− `d e∈κ
Case: D = past
Φ `d prev e ∈ κ

Φ− ` ` e0 ∈ κ by IH on D1
If e = previ M then e0 = previ M by IH on D1
Φ` ` prev e0 ∈ κ by R
If (prev e = previ M ) then (prev e0 = previ M ) by Above

44
D1
Φ+ `d e ∈ κ
Case: D = future
Φ `d next e ∈ κ

Φ+ `` e0 ∈ κ by IH on D1
Φ`` next e0 ∈ κ by future

D1
Φ, u ∈ τ `d e ∈ κ
Case: D = new
Φ `d νu ∈ τ .e ∈ κ

` e0 ∈ κ
Φ, u ∈ τ ` by IH on D1
Φ` ` νu ∈ τ .e0 ∈ κ by new

5.2 Result
Theorem 5.6 (Delphin is Equivalent to LhiΠ cut+ )
The logic presented here, LD is equivalent to LhiΠ cut+ .

Proof: By Lemma 5.4 and Lemma 5.5 

When looking at term-level substitution of LhiΠ cut+ we notice that


the ones corresponding to left-commutative cases of cut propagate what is
being substituted which is counter to what we expect from substitution. For
instance, in order to substitute [(let w = u0 · e0 in f )/u] into an M , where u
occurs free, the following left-commutative case is the only one that applies.
(let w = u0 · e0 in f )
[ ]M ≡ (let w = u0 · e0 in [f /u]M )
u
and here this would correspond to.
(e1 e2 )
[ ]M ≡ (λu ∈ τ .M ) (e1 e2 ), for some τ
u
Therefore, we see that if we use a lazy operational semantics, function
application may simply do nothing and result in itself. However, if we adopt
an eager operational semantics, we get a much more natural definition of

45
substitution and typical behavior. Due to space limitations we omit the
operational semantics, but note that any operational semantics respecting
the term equivalences (which we get from the proof of the admissibility of
cut) is acceptable.
Values in λD remain the same as in Definition 3.10, and are:

v ::= λu ∈ τ .e | unit | M | (v1 , v2 ) | prev v

By inspection of the cases we see that type-level substitution is always


defined when we are substituting a value (in particular a value of the form
prevk M ), or when the substitution is redundant (variable does not occur
free). Thus type-level substitution is defined as follows.

Definition 5.7 Substitution of Delphin Values on Delphin Types.

[v/u](Πu0 ∈ τ .σ) = Πu0 ∈ [v/u]τ .[v/u]σ


[v/u](Σu0 ∈ τ .σ) = Σu0 ∈ [v/u]τ .[v/u]σ
[(prev v)/u]( κ) = ([v/u]κ)
[(prevk M )/u]hAi = h[M/u]LF Ai
[e/u]τ, u not free in τ = τ
None of the above match, [e/u]τ = undefined

And finally if we restrict our term-level substitutions to only substitute


values, we get a much more simplistic definition of term-level substitution
in Delphin.

Definition 5.8 Substitution of Delphin Values on Delphin Terms. Note


that when we write “previ v” we refer to the instance where v is stripped of

46
all its leading prev’s.

v if u = u0

i 0
[(prev v)/u]u ≡
u0 otherwise
[v/u]unit ≡ unit
[v/u](void e) ≡ void (v/u)e
[v/u](λu0 ∈ τ .e) ≡ λu0 ∈ [v/u]τ .[v/u]e
[v/u](e1 e2 ) ≡ ([v/u]e1 ) ([v/u]e2 )
prev ([v 0 /u]e) if v = prev v 0

[v/u](prev e) ≡
prev e otherwise
[v/u](next e) ≡ next([prev v/u]e)
[v/u](e1 , e2 ) ≡ ([v/u]e1 , [v/u]e2 )
[v/u]let (w1 , w2 ) = e in f ≡ let (w1 , w2 ) = [v/u]e in [v/u]f
[v/u](νu ∈ τ .e) ≡ νu0 ∈ [v/u]τ .[v/u]e
0

[M/u]LF N if v = M
[v/u]N ≡
N otherwise

Therefore, we will define Delphin to utilize an eager operational semantics.


With this choice we are guaranteed that substitution is always defined.

6 Case Analysis
The idea of case analysis is conceptually simple, but bares many interesting
facts, primarily due to the presence of dependent types. In the simply
typed scenario, given a variable u ∈ hexpi, where expressions are defined in
Example 2.2, u will be instantiated during run-time by a canonical object Γ `
M : exp. As our logical framework possesses the canonical form property,
a straightforward analysis yields that M = lam (λx : exp .N x), or M =
app N1 N2 or M = x, where x : exp is in Γ. In the first case we may assume
that we can compute N : exp → exp, a variable of functional type, from M .
In the second case we can compute N1 : exp and N2 : exp. In the third case,
we can extract parameter x out of M . It is this last case which we need to
pay careful attention to. When considering cases over a datatype we need
to consider all the ways to construct it and in addition the possibility for
parameters of that type to exist (which is created using new).

47
Therefore we add a case statement to our language.

e, f ::= . . . | case w of (p1 | . . . | pk )


p ::= u ∈ κ .p | ∇u ∈ κ .p | e in f

We write p1 | . . . | pk simply to refer to a list of possible cases (so k ≥ 0). It


may be useful to have 0 cases if the type is uninhabited but this is deferred
to our current work on coverage checking. The  and ∇-quantified variables
represent the pattern variables that can occur in e. We use ∇ to refer to
parameters (introduced by new) and  stands for typical pattern-variables.
Both  and ∇ are treated identically in typing but are operationally distin-
guished where the former can be instantiated with anything but the latter
can only be instantiated with parameters (variables in the context). This
distinction will be illustrated in the examples (Section 8) and is explained
thoroughly in our previous work [Sch05].
We create an auxiliary judgment Φ `w p to represent typing inside a
case of variable w. This judgment collects the pattern variables to the left
of w.
for all 1 ≤ i ≤ k
· ` α wff Φ1 , w ∈ α, Φ2 `w pi ∈ κ
case, k ≥ 0
Φ1 , w ∈ α, Φ2 `d case w of (p1 | . . . | pk ) ∈ κ

Φ1 `d e ∈ α Φ1 , [e/w]Φ2 `d f ∈ [e/w]κ
base
Φ1 , w ∈ α, Φ2 `w (e in f ) ∈ κ

Φ1 , u ∈ κ, w ∈ α, Φ2 `w p ∈ κ0
patternVar
Φ1 , w ∈ α, Φ2 `w (u ∈ κ .p) ∈ κ0

Φ1 , u ∈ κ, w ∈ α, Φ2 `w p ∈ κ0
patternParam
Φ1 , w ∈ α, Φ2 `w (∇u ∈ κ .p) ∈ κ0

The rules patternVar and patternParam simply add pattern variables to


the context and base substitutes the pattern for the variable. Notice impor-
tantly that pattern-variables carry time information which is crucial.
The most important characteristic of the above rules is that in case we
require that we only do cases on closed types, i.e. · ` α wff. At first glance
this may seem problematic for dependently-typed systems. Variables in Φ
may occur in other types as index arguments to LF type families, therefore
it appears that we cannot do case analysis over variables whose types are not

48
closed. For example, based on Example 2.4, Φ could be ·, u ∈ hoi, w ∈ hnd ui.
Therefore we can do case analysis over u but not w. However, we can do
case analysis over Σ types. Therefore, if Φ = ·, u0 ∈ Σu ∈ hoi .hnd ui then
we can do case analysis over u0 . The key insight to case is that in order to
case on hnd ui we are simultaneously doing case also on u.
Therefore, we extend our case statement in a straightforward way to
accept multiple variables imitating the behavior of doing case on a variable
with a Σ type.

e, f ::= . . . | case (w1 , . . . , wm ) of (p1 | . . . | pk )


p ::= u ∈ κ .p | ∇u ∈ κ .p | (e1 , . . . , em ) in f

And the typing derivation is now.

Φ = Φ1 , w1 ∈ α1 , . . . , w2 ∈ α2 , . . . wm ∈ αm , Φ2
· ` (Σw1 ∈ α1 .Σw2 ∈ α2 . . . . αm ) wff
for all 1 ≤ i ≤ k, Φ `(w1 ,...,wm ) pi ∈ κ
case, k ≥ 0
Φ `d case (w1 , . . . , wm ) of (p1 | . . . | pk ) ∈ κ

Φ = Φ1 , w1 ∈ α1 , . . . , w2 ∈ α2 , . . . wm ∈ αm , Φ2
Φ1 `d (e1 , . . . , em ) ∈ (Σw1 ∈ α1 .Σw2 ∈ α2 . . . . αm )
[ we11 ,...,e d e1 ,...,em
,...,wm ]Φ ` f ∈ [ w1 ,...,wm ]κ
m

base
Φ `(w1 ,...,wm ) ((e1 , . . . , em ) in f ) ∈ κ

Φ1 , u ∈ κ, w1 ∈ α1 , Φ2 `(w1 ,...,wm ) p ∈ κ0
patternVar
Φ1 , w1 ∈ α1 , Φ2 `(w1 ,...,wm ) (u ∈ κ .p) ∈ κ0

Φ1 , u ∈ κ, w1 ∈ α1 , Φ2 `(w1 ,...,wm ) p ∈ κ0
patternParam
Φ1 , w1 ∈ α1 , Φ2 `(w1 ,...,wm ) (∇u ∈ κ .p) ∈ κ0

Note that we introduced a shorthand for multiple substitutions [ we11 ,...,w,...,em


m
].
When applied to a type α this is equivalent to to [e1 /w1 ] . . . [em /wm ]α, and is
similarly defined when applied to Φ except that the result of the substitution
removes w1 , . . . , wm from the context. It is best to view these rules as just
an extension of the previous ones from one variable to many.
Due to space limitations we will only briefly talk about the operational
behavior of pattern matching. We defer to the LF unification algorithm
for pattern-matching on terms of type hAi. Pattern matching on other

49
types are straightforward. For instance, pattern matching on pairs is pair-
wise. Matching prev e with prev e0 is successful if we can match e with e0 .
And pattern matching on computational (non-LF) function types is defined
weakly just as syntactic equality. Due to the higher-order nature of our
logical framework, pattern-matching on terms of type hAi is in general not
decidable. In our experience, a decidable fragment of higher-order pattern
matching (which also works for the dependently typed LF) is that of Miller
patterns [Mil91], into which all of our examples fall (especially those in Sec-
tion 8). In addition, a strictness analysis [PS98] on  bound variables can
ensure that their respective instantiations are uniquely determined during
program execution.
In the same spirit of presenting the operational behavior in terms of
equivalence rules, we present the following equivalence rules to illustrate the
behavior of pattern variables.

∇w ∈ k hBi .p ≡ [(prevk w0 )/w]p (1)


k k
w ∈ hBi .p ≡ [(prev N )/w]p (2)

In the above equivalences, both w0 and N must be appropriately well-typed.


With the constructs of ν and case defined, we turn our attention to
provide an example illustrating its behavior.

Example 6.1 (Derivability) Recall from example 2.2 the definition of un-
typed λ-terms in the logical framework as objects of type “exp”.

1. The expression νu ∈ hexpi .hui is not well-formed, because


u ∈ hexpi `d hui ∈ hexpi is not derivable.

2. The expression νu ∈ hexpi .prev hui is not well-formed, because · `d hui ∈ hexpi
is not derivable.

3. The expression

νx ∈ hexpi .[x/y]case y of (e ∈ hexp → expi .


e x in (prev hlam ei))

is well-formed.

e : (exp → exp) ` lam e : exp by LF


e ∈ hexp → expi `d hlam ei ∈ hexpi by hiR
x ∈ hexpi, e ∈ hexp → expi

50
`d prev hlam ei ∈ hexpi by R
x ∈ hexpi, e ∈ hexp → expi
`d (prev hlam ei) ∈ [e x/y]( hexpi) by Substitution

x : exp, e : (exp → exp) ` e x : exp by LF


x ∈ hexpi, e ∈ hexp → expi `d e x ∈ hexpi by hiR

x ∈ hexpi, e ∈ hexp → expi, y ∈ hexpi


`y e x in (prev hlam ei) ∈ hexpi by base
x ∈ hexpi, y ∈ hexpi `y (e ∈ hexp → expi .
e x in (prev hlam ei)) ∈ hexpi by patternVar

· ` exp wff by LF
· `d hexpi wff by hiwffR

x ∈ hexpi, y ∈ hexpi `d case y of (e ∈ hexp → expi .


e x in (prev hlam ei)) ∈ hexpi by case
x ∈ hexpi `d [x/y]case y of (e ∈ hexp → expi .
e x in (prev hlam ei)) ∈ hexpi by Substitution
· `d νx ∈ hexpi .[x/y]case y of (e ∈ hexp → expi .
e x in (prev hlam ei)) ∈ hexpi by new

Example 6.2 (Evaluation) In continuation of the previous example, we


show the evaluation of expression 3 above.
[x/y]case y of (e ∈ hexp → expi .e x in (prev hlam ei))
≡ [x/y]case y of x in (prev hlam (λx0 : exp .x0 )i)
≡ (prev hlam (λx0 : exp .x0 )i)

In Example 6.2 the pattern variable e is substituted with the identity


function. We would not be able to substitute a function where x occurred
free because then it would not type-check in our system. This is exactly the
behavior that we want illustrating how we statically enforce that parameters
cannot escape their scope.

7 General Recursion
Next, we extend Delphin by an explicit recursion operator. In general,
recursion immediately breaks the logical meaning of the calculus, as non-

51
terminating programs cannot be interpreted as proofs unless it is guaranteed
to be well-founded. However, we are now focusing on the computational
aspects. Thus we add a general recursion principle.

e, f ::= . . . | µu ∈ κ .e

which satisfies the usual specification.

Φ, u ∈ κ `d e ∈ κ
rec
Φ `d (µu ∈ κ .e) ∈ κ

and is interpreted operationally as

(µu ∈ κ .e) ≡ [µu ∈ κ .e/u]e. (3)

Unrolling this fix-point means to drive it deeper and deeper into the expres-
sion until no occurrences are left. We give some examples of the recursion
operator next, in Section 8.

8 Examples
Next, we give a few illustrative toy examples of λD -programs. We first
introduce some extra syntactic sugar so we can typeset our programs a little
nicer.

let u = e in f ≡ (λu ∈ τ .f )e
when τ is inferable.

fun f (u1 ∈ τ1 ) (u2 ∈ τ2 ) ≡ µf ∈ (Πu1 ∈ τ1 .Πu2 ∈ τ2 .


. . . (un ∈ τn ) : σ . . . Πun ∈ τn .σ) .
=e λu1 ∈ τ1 . . . . λun ∈ τn .e

We also should mention that for illustrative purposes we explicitly declare


all pattern-variables since the time information on them is crucial in under-
standing the examples. However, -bound pattern variables are relatively
easy to infer (even with the extra time information) and they can be implicit
in Delphin.

52
8.1 Structural Identity
Recall the encoding of the untyped λ-calculus from Example 2.2. We use the
hypothetical judgment E = F to define when two λ-expressions are equal.
u
x=x
..
.
E 1 = F1 E 2 = F2 E=F
cp app cp lamx,u
E1 @E2 = F1 @E2 lam x. E = lam x. F

The judgment can be adequately represented in LF as type family cp and


the two rules as two constants:
cp : exp → exp → type,

cp app : cp E1 F1 → cp E2 F2
→ cp (app E1 E2 ) (app F1 F2 ),

cp lam : (Πx : exp .cp x x → cp (E x) (F x))


→ cp (lam E) (lam F ).

As it is common practice in the logical framework LF we omit the leading


Πs from the types as they can be easily inferred from the free variables that
occur in the types. Next we define the function cpfun ∈ Πe ∈ hexpi .hcp e ei.

fun cpfun (e ∈ hexpi) : hcp e ei


= case e of
E1 ∈ hexpi .E2 ∈ hexpi .(app E1 E2 ) in
let D1 = cpfun E1 in
let D2 = cpfun E2 in
cp app D1 D2
| E 0 ∈ hexp → expi .(lam E 0 ) in
next (νx ∈ hexpi .νu ∈ hcp x xi .
let D0 = cpfun (E 0 x) in
case D0 of D ∈ hΠx : exp .cp x x
→ cp (E 0 x) (E 0 x)i .
(D x u) in
prev (cp lam D)
| ∇x ∈ hexpi .∇u ∈ hcp x xi .x in u

53
We explain each of the three cases in turn. The e = app E1 E2 case
is straightforward. The result of the recursive calls is combined into the
desired proof by cp app.
The e = lam E 0 case illustrates our ability to go under representation-
level λ’s using next and ν. next brings us one step into the future, its type
τ ensures that the result can be interpreted in the present. Next, we create
a new parameter x and recurse on E 0 x. The result is valid in the future.
To ensure that the type checker knows that we eventually return to the
present, we stipulate D to exist in the past, which is sufficient to guarantee
that “prev cp lam D” is valid now. Thus neither x nor u can escape their
scope.
The final case is the parameter case. There will be only one u ∈ hcp x xi
in the context during runtime, which is promptly returned. This illustrates
the difference between ∇ and . Variables bound by ∇ are only instantiated
by parameters, which are introduced by new. Variables bound by  can be
instantiated with anything. If we replaced the ∇ quantified variables in the
last case with ’s then since the pattern is just x, this branch could non
deterministically return anything.
In this example there is no nondeterministic behavior because all pattern
variables occur strict [PS98] in the pattern. We will exploit the nondeter-
ministic behavior later in our theorem prover example. However, we can
eliminate the nondeterminism by making sure that pattern variables occur
strict in the pattern. In the implementation we can generate a warning if it
doesn’t.

8.2 Combinators
Recall the definition of the natural deduction calculus from Example 2.4. We
will give an algorithmic procedure that converts natural deduction deriva-
tions into the Hilbert calculus.
`o⊃p `o
K MP
`o⊃p⊃o `p
S
` (o ⊃ p ⊃ q) ⊃ (o ⊃ p) ⊃ (o ⊃ q)

54
Following the standard Judgments-as-types paradigm, our encoding is:

comb : o → type,

pKq = K: comb (A ⇒ B ⇒ A)
pSq = S: comb ((A ⇒ B ⇒ C) ⇒ (A ⇒ B)
⇒ A ⇒ C)
pM P q = MP : comb(A ⇒ B) → comb A → comb B

Any of our simply-typed λ-expressions, exp can be converted into a


combinator in a two-step algorithm. The first step is called bracket ab-
straction, or ba, which converts a parametric combinator into a combinator
with one less parameter . If M has type hcomb A → comb Bi and N has type
hcomb Ai then we can use ba to get a combinator, u, of type hcomb A ⇒ Bi.
Then we can do MP u N to get a term that is equivalent to hM N i in com-
binator logic. Formally, ba is written as.

55
fun ba (A ∈ hoi) (B ∈ hoi) (F ∈ hcomb A → comb Bi)
: hcomb A ⇒ Bi
= case (A, B, F ) of
A ∈ hoi .B ∈ hoi .∇z ∈ hcomb Bi .(A, B, λx : comb A .z)
in (MP K z)

| A ∈ hoi .(A, A, λx : comb A .x)


in (MP (MP S K) K)

| A ∈ hoi .C ∈ hoi .D ∈ hoi .


(A, C ⇒ D ⇒ C, λx : comb A .K)
in (MP K K)

| A ∈ hoi .C ∈ hoi .D ∈ hoi .E ∈ hoi .


(A,
(C ⇒ D ⇒ E) ⇒ (C ⇒ D) ⇒ C ⇒ E,
λx : comb A .S)
in (MP K S)

| A ∈ hoi .B ∈ hoi .C ∈ hoi .


D1 ∈ hcomb A → comb (C ⇒ B)i .
D2 ∈ hcomb A → comb Ci .
(A, B, λx : comb A .MP (D1 x) (D2 x))
in
let D10 = ba A (C ⇒ B) D1 in
let D20 = ba A C D2 in
MP (MP S D10 ) D20

The first two cases of ba illustrate how to distinguish x, which is to be ab-


stracted, from parameters (∇z) that are introduced in the function convert,
which we discuss next. The function convert traverses natural deduction
derivation and uses ba to convert them into Hilbert style combinators.

56
fun convert (A ∈ hoi) (D ∈ hnd Ai) : hcomb Ai
= case (A, D) of
A ∈ hoi .∇u ∈ hcomb A → nd Ai .∇c ∈ hcomb Ai .
(A, u c)
in c

| A ∈ hoi .B ∈ hoi .


D1 ∈ hnd (B ⇒ A)i .D2 ∈ hnd Bi .
(A, impe D1 D2 )
in
let C1 = convert (B ⇒ A) D1 in
let C2 = convert B D2 in
(MP C1 C2 )

| B ∈ hoi .C ∈ hoi .D ∈ hnd B → nd Ci .


(B ⇒ C, impi D)
in
next (νu ∈ hcomb B → nd Bi .νb ∈ hcomb Bi .
let D0 = convert B (D (u b)) in
case D0 of D00 ∈ hcomb B → comb Ci .
(D00 b) in prev (ba B C D00 ))

The last case illustrates how a parameter of functional type may intro-
duce information to be used when the parameter is matched. Rather than
introduce a parameter u of type hnd Bi, we introduce a parameter of type
hcomb B → nd Bi that carries a combinator as “payload.” In our exam-
ple, the payload is another parameter b ∈ hcomb Bi, the image of u under
convert. This technique is known as payload-carrying parameters and is
applicable to a wide range of examples [Sch05].

8.3 Theorem Prover


Next we illustrate how the non-deterministic instantiation of  bound pa-
rameters can be used to implement a very simple and naive proof search
procedure. Our theorem prover constructs derivation in the natural deduc-
tion calculus from Example 2.4 from a formula A. The function prove ∈
ΠA ∈ hoi .hnd Ai and and solve ∈ ΠA ∈ hoi .ΠC ∈ hoi .hnd Ci ⊃ hnd Ai are
defined mutually recursively. The former constructs a proof for A, and the

57
latter applies impe to proofs of C in the hope to discover a proof of A.

fun prove (A ∈ hoi) : hnd Ai

= case A of

∇p ∈ hoi .C ∈ hoi .∇u ∈ hnd Ci .


p in solve hpi hCi u

| ∇A0 ∈ hoi .∇B 0 ∈ hoi .


(A0 ⇒ B 0 ) in
next (νu ∈ hnd A0 i .
let D0 = prove B 0 in
case D0 of D ∈ hnd A0 → nd B 0 i .
(D u) in prev (impi D))

and fun solve (A ∈ hoi) (C ∈ hoi) (D ∈ hnd Ci) : hnd Ai


= case (A, C) of
A ∈ hoi .(A, A) in D
| A ∈ hoi .∇A0 ∈ hoi .∇B 0 ∈ hoi .
(A, A0 ⇒ B 0 ) in
let D0 = prove A0 in
solve A B 0 (impe D0 D)

9 Related Work
Both research with higher-order and abstract syntax and research with pro-
gramming with dependent types are related to the λD -calculus.

Higher-order abstract syntax. The λD -calculus is the result of many


years of design, originally inspired by an extension to ML proposed by Dale
Miller [Mil90], the type theory Tω+ [Sch01], and Hofmann’s work on higher-
order abstract syntax [Hof99]. It extends the ∇-calculus [Sch05] by de-
pendent types, but more importantly, it gives a clean and logical account

58
of programming with higher-order encodings without being confined by a
rigidly defined iteration construct as proposed in [SDP01] and [Lel98],
which separates representation-level from computation-level functions via a
modality within one single λ-calculus.
Closely related to our work are programming languages with freshness [GP99],
which provide a built-in α-equivalence relation for first-order encodings but
provide neither βη nor any support for higher-order encodings. Also closely
related are meta-programming languages, such as MetaML [TS00], which
provide hierarchies of computation levels but do not single out a particular
level for representation. Many other attempts have been made to combine
higher-order encodings and functional programming, in particular Honsell,
Miculan, and Scagnetto’s embedding of the π-calculus in Coq[HMS01], and
Momigliano, Amber, and Crole’s Hybrid system [MAC03].

Dependent types The λD -calculus is not the first to attempt to com-


bine dependent-types with functional programming. DML [XP99] used to
have index datatypes, whose index domains were recently generalized to LF
objects [CX05] to form the ATS/LF system. Both Cayenne [Aug98] and
Epigram [MM04] are dependently typed functional languages. Westbrook’s
et al. system [WaIW05] is designed for verified imperative programming with
dependent types. All but the ATS/LF system support dependent types but
lack support for higher-order encodings and are motivated by quite different
goals. ATS/LF can explicitly manipulate contexts, and may be the closest
to our calculus. Cayenne combines dependent-types and first class types,
thus making more programs typeable. These languages differ radically from
the λD -calculus in their structural design. Our calculus is a three-tiered
language. Its upper two layers, a recursive function space used for compu-
tation, is entirely separate from its lower representation (LF) layer, which
is used for data representation. By contrast, DML and Cayenne introduce
dependent types directly into the type system of the host language. DML
only uses restricted dependent types; type index objects are drawn from a
constraint domain which is much less powerful than LF’s λΠ type system.
DML and Cayenne also differ with respect to the data structures that can
be easily supported by the language. Because dependent types in DML and
Cayenne are introduced for typing purposes only, their data structures are
the same as those provided by the respective host languages. Thus it is still
very cumbersome to program with complex data structures such as those
which represent proofs or typing derivations. The λD -calculus is specifically
designed to support programs that can easily represent and operate upon

59
such complex data structures.
Epigram [MM04] is a novel system based on Lego, which provides a
functional calculus of total functions, it stops short, however of providing
higher-order encodings.
Our work is based upon our earlier work with the ∇-calculus [Sch05]
which lacked dependent-types and followed a more ad-hoc approach than
our logically motivated work here. Our work with the ∇-calculus has also
inspired Westbrook’s similar work called λF V [Wes06]. This calculus is de-
signed to include coverage checking in the type-system. Work on λF V is still
ongoing, including a proof for type safety.

10 Conclusion
In this paper we have given a formulation of temporal logic designed to
reason about derivations under a different logic at different times. It is
being turned into a novel programming language, which is called Delphin
and currently under development. Please visit www.cs.yale.edu/∼delphin for
more information. And finally, with the appropriate syntactical enforceable
side conditions of coverage and termination, λD is a meta-logic for the logical
framework LF.
We have shown examples of programming with proofs including combi-
nator transformations and theorem proving. In future work we will study
meta-theoretic properties of the system including coverage and termination,
which will allow us to guarantee that our functions are complete proofs. We
are also concentrating on the implementation efforts.

60
A Appendix: Twelf Proofs
A.1 sources.cfg
num.elf
formulas.elf
seq.elf
lfProps.elf
seqProps.elf
shiftSeq.elf
cutAdmis.elf
natDed.elf
natToSeq.elf
seqToNat.elf
examples.elf

61
A.2 num.elf
% Adam Poswolsky
% Properties of numbers
% Here we encode natural numbers and prove some properties.

% Representation of Natural Numbers


% We use X,Y to stand for natural numbers.
nat : type. %name nat (X Y) (x y).
z : nat.
s : nat -> nat.

% Encoding of less than or equal to relation.


le : nat -> nat -> type. %name le L.
%mode le +X +Y.
base : le X X.
one : le X Y -> le X (s Y).

leAddOneRight : le X Y -> le X (s Y) -> type.


%mode leAddOneRight +L -L’.
leAddOneRightCase : leAddOneRight L (one L).
%worlds () (leAddOneRight _ _).
%total {L} (leAddOneRight L _).

leRemoveOneLeft : le (s X) Y -> le X Y -> type.


%mode leRemoveOneLeft +L -L’.
leRemoveOneLeftBase : leRemoveOneLeft base (one base).
leRemoveOneLeftInd : leRemoveOneLeft (one L) (one L’)
<- leRemoveOneLeft L L’.
%worlds () (leRemoveOneLeft _ _).
%total {L} (leRemoveOneLeft L _).

leAddOneBoth : le X Y -> le (s X) (s Y) -> type.


%mode leAddOneBoth +L -L’.
leAddOneBoth_base: leAddOneBoth base base.
leAddOneBoth_ind: leAddOneBoth (one L) (one L’)
<- leAddOneBoth L L’.
%worlds () (leAddOneBoth _ _).
%total {L} (leAddOneBoth L _).

leRemoveOneBoth : le (s X) (s Y) -> le X Y -> type.


%mode leRemoveOneBoth +L -L’.
leRemoveOneBothBase : leRemoveOneBoth base base.
leRemoveOneBothInd : leRemoveOneBoth (one L) L’
<- leRemoveOneLeft L L’.
%worlds () (leRemoveOneBoth _ _).
%total {L} (leRemoveOneBoth L _).

leTrans: le X1 X2 -> le X2 X3 -> le X1 X3 -> type.


%mode leTrans +L1 +L2 -L3.
leTransBase : leTrans L base L.
leTransInd : leTrans L1 (one L2) (one L3)
<- leTrans L1 L2 L3.
%worlds () (leTrans _ _ _).
%total {L1 L2} (leTrans L1 L2 _).

%
% Show it is impossible for le (s X) X
%
emptyType : type. %name emptyType EE.

impossibleLessNum : {X} le (s X) X -> emptyType -> type.


%mode +{X:nat} +{L:le (s X) X} -{EE:emptyType}
(impossibleLessNum X L EE).

impossibleLessNumOne : impossibleLessNum (s X) (one L) EE


<- leRemoveOneLeft L L’
<- impossibleLessNum X L’ EE.

%worlds () (impossibleLessNum _ _ _).

62
%terminates {X} (impossibleLessNum X _ _).
%total {X} (impossibleLessNum X _ _).

63
A.3 formulas.elf
% Adam Poswolsky
% Encoding of our language
% And Properties on Formulas themselves.

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Representation-Level
% A,B ::= a (type constant) | A arrow B
% Note: We will use M,N for the objects.
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

lftp : type. %name lftp (A B) (a b).


arrow : lftp -> lftp -> lftp. %infix right 10 arrow.
% We include a block to represent type constants
% that may exist.
%block lftypeConsBlock : block {A:lftp}.

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Meta-Level
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Formulas T,S ::= top, bot, T imp S, past T, inj A
% Note: We will use D,E for the objects.
%
% However, for our encoding we make a distinction
% between those types starting with "past". All
% proofs will be over all formulas, "o", but this
% distinction helps because we often want to distinguish
% between it being "past" or anything else.
%
% The reason for this is that our system requires
% that changes are made to the context. Namely, the
% number of pasts in front of everything in the context
% can go up or down. The trick we will use to capture this
% (see seq.elf) takes advantage of this restriction.
%
%

o : type. %name o (T S) (t s).


pureO : type. %name pureO (TP SP) (tp sp).

top : pureO.
bot : pureO.
imp : pureO -> pureO -> pureO. %infix right 10 imp.
inj : lftp -> pureO.
pair : pureO -> pureO -> pureO.

! : pureO -> o.
past: o -> o.

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Properties
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%
% stripPast +X1 +T1 -X2 -T2
% This will strip away all pasts in front of T1 yielding T2.
% And X2 = X1 - (number of leading pasts of T1)
%
stripPast : nat -> o -> nat -> pureO -> type. %name stripPast SP.
stripPastPure : stripPast X (! TP) X TP.
stripPastPast : stripPast X1 T1 X2 TP -> stripPast (s X1) (past T1) X2 TP.

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Some Props of stripPast
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

stripToLess : stripPast X1 T1 X2 TP -> le X2 X1 -> type.


%mode stripToLess +SP -L.
stripToLessPure : stripToLess stripPastPure base.
stripToLessPast : stripToLess (stripPastPast SP) L’

64
<- stripToLess SP L
<- leAddOneRight L L’.
%worlds (lftypeConsBlock) (stripToLess _ _).
%total {SP} (stripToLess SP _).

stripAddOne : stripPast X1 T1 X2 TP -> stripPast (s X1) T1 (s X2) TP -> type.


%mode stripAddOne +SP -SP’.
stripAddOnePure : stripAddOne stripPastPure stripPastPure.
stripAddOnePast : stripAddOne (stripPastPast SP) (stripPastPast SP’)
<- stripAddOne SP SP’.
%worlds (lftypeConsBlock) (stripAddOne _ _).
%total {SP} (stripAddOne SP _).

65
A.4 seq.elf
% Adam Poswolsky
% Encoding of Sequent Calculus version

%{
IMPORTANT: How to read the rules:

Our system needs to be able to add or subtract "past"


from all elements in the context. In order to encode this
we design our judgment with an index N such that if N goes up
it is interpreted as adding a past to everything in the context.

Therefore, when reading the rules one must keep in mind that:

% !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
% !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
hyp X T -> conc Y S
is meant to be interpreted as:

(past ... past T) |--- S


where the number of leading pasts to T is (Y - X)
% !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
% !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Notice that this also means that


hyp X T -> conc Y S
is the same as
hyp (X+1) (past T) -> conc Y S

In other encodings of this sytem we allowed this


and then had an "equiv" relation to tell when they
are equal. However, that introduced a lot of overhead
(see old directory).

Instead, here we disallow the second representation.


This explains us distinguishing between types
that do not start with a past (pureO) and those that
can be anything (o). "hyp" allows contain a
type without any leading pasts (so the fact that there
were leading pasts is captures in the index).

}%

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Context (explained above)
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
hyp : nat -> pureO -> type. %name hyp H (h sh).
%block hypBlock : some {X:nat}{TP:pureO} block {h:hyp X TP}.

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Representation-Level
% M,N ::= c (object constant) | lam x:A.M | app M N
%
% The "casting" operation is captures by castHyp with
% shiftLF
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

exp : nat -> lftp -> type. %name exp (M N) (m n).


lam : (exp X A -> exp X B) -> exp X (A arrow B).
app : exp X (A arrow B)-> exp X A -> exp X B.
shiftLF : exp X A -> exp (s X) A.
castHyp : hyp X (inj A) -> exp X A.
%
% %%%%%%%%%%%%%%%%
% The lfexpBlock can also be thought of
% as representing the constants "c" that
% exist in the signature.
% %%%%%%%%%%%%%%%%
%block lfexpBlock : some {X:nat}{A:lftp} block {m:exp X A}.

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Meta-Level

66
% (actual rule is placed in comments before encoded rule)
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
conc : nat -> o -> type. %name conc (D E F) (d e f).

%{ AXIOM
T is in Omega
--------------- axiom, where |T| removes leading pasts of T
Omega |-- |T|
}%
axiom : le X Y -> hyp X TP -> conc Y (! TP).

%{ IMPR
Omega, TP1 |-- TP2
--------------------- impr
Omega |-- TP1 imp TP2
}%
impr : (hyp X TP1 -> conc X (! TP2))
-> conc X (! (TP1 imp TP2)).

%{ IMPL
(past...past)(TP1 imp TP2) in Omega,
Omega |-- TP1 Omega,TP2 |--- S
---------------------------------- impl
Omega |-- S
}%
impl : le X Y -> hyp X (TP1 imp TP2) -> conc Y (! TP1)
-> (hyp Y TP2 -> conc Y (! S)) -> conc Y (! S).

%{ TOP

--------------- topr
Omega |--- top
}%
topr : conc _ (! top).

%{ BOTL

-------------------------------------- botl
Omega,(past...past)bot,Omega’ |--- TP
}%
botl : le X Y -> hyp X bot -> conc Y (! TP).

%{ PASTR
(remove past from Omega) |-- T
------------------------------------- pastr
Omega |-- past T

}%
pastr : conc X T -> conc (s X) (past T).

%{ INJR
(cast Omega to LF) |-- A
------------------------------------- injr
Omega |-- inj A

}%
injr : exp X A -> conc X (! (inj A)).

%{ PAIRR
Omega |-- TP1 Omega |-- TP2
------------------------------------ pairr
Omega |-- pair TP1 TP2
}%
pairr : conc X (! TP1) -> conc X (! TP2) -> conc X (! (pair TP1 TP2)).

%{ PAIRL
(past...past)(pair TP1 TP2) in Omega,
Omega, TP1, TP2 |--- S

67
-------------------------------------- pairl
Omega |-- S
}%
pairl : le X Y -> hyp X (pair TP1 TP2)
-> (hyp Y TP1 -> hyp Y TP2 -> conc Y (! S))
-> conc Y (! S).

68
A.5 lfProps.elf
% Adam Poswolsky
% Properties of the Representation-Level (LF) of our system.

% This is used when we encounter a case that is impossible


fromEmptyComesAllLF : emptyType -> exp X A -> type.
%mode +{X:nat} +{A:lftp} +{EE:emptyType} -{M:exp X A} (fromEmptyComesAllLF EE M).
%worlds (hypBlock | lfexpBlock | lftypeConsBlock) (fromEmptyComesAllLF _ _).
%total {EE} (fromEmptyComesAllLF EE _).

%
% There is no "past" on the LF level itself, so we have more freedom
% with the index. Namely if (exp Y A -> exp X B) and Y <= X, then
% we can change it to (exp Y’ A -> exp X B) where Y’ can be anything <= X.
%
shiftNegExpLF : le (s Y) X -> (exp Y A -> exp X B) -> (exp (s Y) A -> exp X B) -> type.
%mode shiftNegExpLF +L +M -M2.
shiftNegExpLFLam : shiftNegExpLF L ([n] lam (M n)) ([n] lam (M’ n))
<- ({m} shiftNegExpLF L ([n] M n m) ([n] M’ n m)).
shiftNegExpLFApp : shiftNegExpLF L ([n] app (M1 n) (M2 n)) ([n] app (M1’ n) (M2’ n))
<- shiftNegExpLF L M1 M1’
<- shiftNegExpLF L M2 M2’.
shiftNegExpLFShift1 : shiftNegExpLF base ([n] shiftLF (M n)) ([n] app (shiftLF (lam M)) n).

shiftNegExpLFShift2 : shiftNegExpLF (one L) ([n] shiftLF (M n)) ([n] shiftLF (M’ n))
<- shiftNegExpLF L M M’.

shiftNegExpLFCast1 : shiftNegExpLF L ([n] castHyp H) ([n] castHyp H).


shiftNegExpLFBlockCase : shiftNegExpLF L ([_] M) ([_] M).
shiftNegExpLFidentity : shiftNegExpLF L ([n] n) ([n] M n)
<- impossibleLessNum _ L EE
<- ({m} fromEmptyComesAllLF EE (M m)).

%worlds ( hypBlock | lfexpBlock | lftypeConsBlock) (shiftNegExpLF _ _ _).


%total {L M} (shiftNegExpLF L M _).

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This is an important judgment which says that if we have a function
% from (hyp Y (inj A) -> exp X B) then we can create (exp Y A -> exp X B)
%
% Note that the reverse direction is trivial (just use castHyp)
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
convertHypExp : (hyp Y (inj A) -> exp X B) -> (exp Y A -> exp X B) -> type.
%mode convertHypExp +M -M2.
convertHypExpLam : convertHypExp ([h] lam (M h)) ([n] lam (M’ n))
<- ({m} convertHypExp ([h] M h m) ([n] M’ n m)).
convertHypExpApp : convertHypExp ([h] app (M1 h) (M2 h)) ([n] app (M1’ n) (M2’ n))
<- convertHypExp M1 M1’
<- convertHypExp M2 M2’.
convertHypExpShift : convertHypExp ([h] shiftLF (M h)) ([n] shiftLF (M’ n))
<- convertHypExp M M’.

convertHypExpCast1 : convertHypExp ([_] castHyp H) ([_] castHyp H).


convertHypExpCast2 : convertHypExp ([h] castHyp h) ([n] n).

convertHypExpBlockCase : convertHypExp ([_] M) ([_] M).


%worlds ( hypBlock | lfexpBlock | lftypeConsBlock) (convertHypExp _ _).
%total {M} (convertHypExp M _).

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Strengthening (#1)
%
% if (hyp Y TP -> exp X A) and TP is not an Inj, then the function
% cannot use its argument.
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
notInj : pureO -> type. %name notInj NI ni.
notInjImp : notInj (TP1 imp TP2).
notInjPair : notInj (pair TP1 TP2).
notInjTop : notInj top.
notInjBot : notInj bot.

69
strengthenLFNI : notInj TP -> (hyp Y TP -> exp X A) -> exp X A -> type.
%mode strengthenLFNI +NI +M -M2.
strengthenLFNILam : strengthenLFNI NI ([h] lam (N h)) (lam N’)
<- ({m} strengthenLFNI NI ([h] N h m) (N’ m)).
strengthenLFNIApp : strengthenLFNI NI ([h] app (N1 h) (N2 h)) (app N1’ N2’)
<- strengthenLFNI NI N1 N1’
<- strengthenLFNI NI N2 N2’.
strengthenLFNIShift : strengthenLFNI NI ([h] shiftLF (N h)) (shiftLF N’)
<- strengthenLFNI NI N N’.
strengthenLFNICast : strengthenLFNI NI ([h] castHyp H) (castHyp H).
strengthenLFNIBlockCase : strengthenLFNI NI ([h] N) N.
%worlds ( hypBlock | lfexpBlock | lftypeConsBlock) (strengthenLFNI _ _ _).
%total {N} (strengthenLFNI _ N _).

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Strengthening (#2)
%
% If (hyp Y TP -> exp X A) and Y > X, then the function cannot
% use its argument.
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

strengthenLF : le Y X -> (hyp (s X) TP -> exp Y B) -> exp Y B -> type.


%mode strengthenLF +L +M -M2.
strengthenLFLam : strengthenLF L ([h] lam (M h)) (lam M’)
<- ({m} strengthenLF L ([h] M h m) (M’ m)).
strengthenLFApp : strengthenLF L ([h] app (M1 h) (M2 h)) (app M1’ M2’)
<- strengthenLF L M1 M1’
<- strengthenLF L M2 M2’.
strengthenLFShift : strengthenLF L ([h] shiftLF (M h)) (shiftLF M’)
<- leRemoveOneLeft L L’
<- strengthenLF L’ M M’.
strengthenLFCast1 : strengthenLF L ([h] castHyp H) (castHyp H).
strengthenLFCast2 : strengthenLF L ([h] castHyp h) M
<- impossibleLessNum _ L EE
<- fromEmptyComesAllLF EE M.
strengthenLFBlockCase : strengthenLF L ([h] M) M.
%worlds ( hypBlock | lfexpBlock | lftypeConsBlock) (strengthenLF _ _ _).
%total {M} (strengthenLF _ M _).

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Strengthening (#3)
%
% If (exp Y B -> exp X A) and Y > X, then the function cannot
% use its argument.
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
strengthenLF2 : le Y X -> (exp (s X) A -> exp Y B) -> exp Y B -> type.
%mode strengthenLF2 +L +M -M2.
strengthenLF2Lam : strengthenLF2 L ([n] lam (M n)) (lam M’)
<- ({m} strengthenLF2 L ([n] M n m) (M’ m)).
strengthenLF2App : strengthenLF2 L ([n] app (M1 n) (M2 n)) (app M1’ M2’)
<- strengthenLF2 L M1 M1’
<- strengthenLF2 L M2 M2’.
strengthenLF2Shift : strengthenLF2 L ([n] shiftLF (M n)) (shiftLF M’)
<- leRemoveOneLeft L L’
<- strengthenLF2 L’ M M’.
strengthenLF2Identity : strengthenLF2 L ([n] n) M
<- impossibleLessNum _ L EE
<- fromEmptyComesAllLF EE M.
strengthenLF2BlockAndCast : strengthenLF2 L ([m] M) M.
%worlds ( hypBlock | lfexpBlock | lftypeConsBlock) (strengthenLF2 _ _ _).
%total {M} (strengthenLF2 _ M _).

70
A.6 seqProps.elf
% Adam Poswolsky
% Properties of our Meta-Level
% This includes reversing pastr (future rule),
% Weakening, and Strengthening.

% This is used when we encounter a case that is impossible


fromEmptyComesAll : emptyType -> conc X T -> type.
%mode +{X:nat} +{T:o} +{EE:emptyType} -{D:conc X T} (fromEmptyComesAll EE D).
%worlds (hypBlock | lfexpBlock | lftypeConsBlock) (fromEmptyComesAll _ _).
%total {EE} (fromEmptyComesAll EE _).

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Weakening... for example, if Omega,A |-- B then Omega,(past A) |-- B
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
weakenHypLF’ : (hyp (s X) TP -> exp Y B) -> (hyp X TP -> exp Y B) -> type.
%mode weakenHypLF’ +M1 -M2.
weakenHypLF’Lam : weakenHypLF’ ([sh] lam (M sh)) ([h] lam (M’ h))
<- ({m} weakenHypLF’ ([sh] M sh m) ([h] M’ h m)).
weakenHypLF’App : weakenHypLF’ ([sh] app (M1 sh) (M2 sh)) ([h] app (M1’ h) (M2’ h))
<- weakenHypLF’ M1 M1’
<- weakenHypLF’ M2 M2’.
weakenHypLF’Shift : weakenHypLF’ ([sh] shiftLF (M sh)) ([h] shiftLF (M’ h))
<- weakenHypLF’ M M’.
weakenHypLF’Cast1 : weakenHypLF’ ([sh] castHyp H) ([h] castHyp H).
weakenHypLF’Cast2 : weakenHypLF’ ([sh] castHyp sh) ([h] (shiftLF (castHyp h))).
weakenHypLF’BlockCase : weakenHypLF’ ([sh] M) ([h] M).
%worlds (hypBlock | lfexpBlock | lftypeConsBlock) (weakenHypLF’ _ _).
%total {M} (weakenHypLF’ M _).

weakenHyp’ : (hyp (s X) TP -> conc Y S) -> (hyp X TP -> conc Y S) -> type.
%mode weakenHyp’ +F1 -F2.
weakenHyp’Axiom1 : weakenHyp’ ([sh] axiom L H) ([h] axiom L H).
weakenHyp’Axiom2 : weakenHyp’ ([sh] axiom L sh) ([h] axiom L’ h)
<- leRemoveOneLeft L L’.

weakenHyp’Impr : weakenHyp’ ([sh] impr (D sh)) ([h] impr (D’ h))


<- ({h2} weakenHyp’ ([sh] D sh h2) ([h] D’ h h2)).

weakenHyp’Impl1 : weakenHyp’ ([sh] impl L H (D1 sh) (D2 sh))


([h] impl L H (D1’ h) (D2’ h))
<- weakenHyp’ D1 D1’
<- ({h2} weakenHyp’ ([sh] D2 sh h2) ([h] D2’ h h2)).

weakenHyp’Impl2 : weakenHyp’ ([sh] impl L sh (D1 sh) (D2 sh))


([h] impl L’ h (D1’ h) (D2’ h))
<- weakenHyp’ D1 D1’
<- ({h2} weakenHyp’ ([sh] D2 sh h2) ([h] D2’ h h2))
<- leRemoveOneLeft L L’.

weakenHyp’Top : weakenHyp’ ([sh] topr) ([h] topr).


weakenHyp’Botl1 : weakenHyp’ ([sh] botl L H) ([h] botl L H).
weakenHyp’Botl2 : weakenHyp’ ([sh] botl L sh) ([h] botl L’ h)
<- leRemoveOneLeft L L’.

weakenHyp’Pastr : weakenHyp’ ([sh] pastr (D sh)) ([h] pastr (D’ h))


<- weakenHyp’ D D’.

weakenHyp’Injr : weakenHyp’ ([sh] injr (M sh)) ([h] injr (M’ h))


<- weakenHypLF’ M M’.

weakenHyp’Pairr : weakenHyp’ ([sh] pairr (D1 sh) (D2 sh)) ([h] pairr (D1’ h) (D2’ h))
<- weakenHyp’ D1 D1’
<- weakenHyp’ D2 D2’.

weakenHyp’Pairl1 : weakenHyp’ ([sh] pairl L H (D sh))


([h] pairl L H (D’ h))
<- ({h2}{h3} weakenHyp’ ([sh] D sh h2 h3) ([h] D’ h h2 h3)).

weakenHyp’Pairl2 : weakenHyp’ ([sh] pairl L sh (D sh))


([h] pairl L’ h (D’ h))
<- ({h2}{h3} weakenHyp’ ([sh] D sh h2 h3) ([h] D’ h h2 h3))
<- leRemoveOneLeft L L’.

71
%worlds (hypBlock | lfexpBlock | lftypeConsBlock) (weakenHyp’ _ _).
%total {F} (weakenHyp’ F _).

weakenHyp : le X2 X1 -> (hyp X1 TP -> conc X* S*) -> (hyp X2 TP -> conc X* S*) -> type.
%mode weakenHyp +L +E1 -E2.
weakenHypBase : weakenHyp base E1 E1.
weakenHypOne : weakenHyp (one L) E1 E2
<- weakenHyp’ E1 E1’
<- weakenHyp L E1’ E2.
%worlds (hypBlock | lfexpBlock | lftypeConsBlock) (weakenHyp _ _ _).
%total {L} (weakenHyp L _ _).

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Strengthening... (Part 1 of 2)
% if (hyp X TP -> conc Y T) and X > Y, then
% the function doesn’t use its argument.
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
strengthen : le Y X -> (hyp (s X) TP -> conc Y T) -> conc Y T -> type.
%mode strengthen +L +E -D.
strengthenAxiom1 : strengthen L ([h] axiom L’ H) (axiom L’ H).
strengthenAxiom2 : strengthen L ([h] axiom L’ h) D
<- leAddOneBoth L L1
<- leTrans L1 L’ L2
<- impossibleLessNum _ L2 EE
<- fromEmptyComesAll EE D.

strengthenImpr : strengthen L ([h] impr (D h)) (impr D’)


<- ({h’} strengthen L ([h] D h h’) (D’ h’)).

strengthenImpl1 : strengthen L ([h] impl L’ H (D1 h) (D2 h)) (impl L’ H D1’ D2’)
<- strengthen L D1 D1’
<- ({h’} strengthen L ([h] D2 h h’) (D2’ h’)).
strengthenImpl2 : strengthen L ([h] impl L’ h (D1 h) (D2 h)) D
<- leAddOneBoth L L1
<- leTrans L1 L’ L2
<- impossibleLessNum _ L2 EE
<- fromEmptyComesAll EE D.

strengthenTopr : strengthen L ([h] topr) (topr).


strengthenBotl1 : strengthen L ([h] botl L’ H) (botl L’ H).
strengthenBotl2 : strengthen L ([h] botl L’ h) D
<- leAddOneBoth L L1
<- leTrans L1 L’ L2
<- impossibleLessNum _ L2 EE
<- fromEmptyComesAll EE D.

strengthenPastr : strengthen L ([h] pastr (D h)) (pastr D’)


<- leRemoveOneLeft L L’
<- strengthen L’ D D’.

strengthenInjr : strengthen L ([h] injr (M h)) (injr M’)


<- strengthenLF L M M’.

strengthenPairr : strengthen L ([h] pairr (D1 h) (D2 h)) (pairr D1’ D2’)
<- strengthen L D1 D1’
<- strengthen L D2 D2’.

strengthenPairl1 : strengthen L ([h] pairl L’ H (D h)) (pairl L’ H D’)


<- ({h’}{h’’} strengthen L ([h] D h h’ h’’) (D’ h’ h’’)).

strengthenPairl2 : strengthen L ([h] pairl L’ h (D h)) D’


<- leAddOneBoth L L1
<- leTrans L1 L’ L2
<- impossibleLessNum _ L2 EE
<- fromEmptyComesAll EE D’.

%worlds ( hypBlock | lfexpBlock | lftypeConsBlock) (strengthen _ _ _).


% reduces won’t work here ... %reduces D’ <= D (strengthen _ D D’).
%total {D} (strengthen _ D _).

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Important Admissible Rule:
% We now define the future rule (reverse of pastr).

72
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

futureRule : conc (s X) (past T) -> conc X T -> type.


%mode futureRule +D -D’.

futureRulePastr : futureRule (pastr D) D.


%worlds (hypBlock | lfexpBlock | lftypeConsBlock)
(futureRule _ _).
%covers (futureRule +D -D’).
%terminates {D} (futureRule D _).
%total {D} (futureRule D _).

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Strengthening... (Part 2 of 2)
% if Omega,A |-- (past B)
% and A is not (past A*), then Omega |-- (past B)
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

strengthenP : (hyp X _ -> conc X (past T)) -> conc X (past T) -> type.
%mode strengthenP +D -D’.
strengthenPcase : strengthenP D (pastr E’)
<- ({h} futureRule (D h) (D’ h))
<- strengthen base D’ E’.

%worlds(hypBlock | lfexpBlock | lftypeConsBlock) (strengthenP _ _).


%covers (strengthenP +D -D’).
%total {D} (strengthenP D _).

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% equivalent Conclusion
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
equivConc : conc X T -> stripPast X T Y TP -> conc Y (! TP) -> type.
%mode equivConc +D1 +SP -E.
equivConcSPbase : equivConc E SP E.
equivConcSPpast : equivConc D1 (stripPastPast SP) E
<- futureRule D1 D1’
<- equivConc D1’ SP E.
%worlds (hypBlock | lfexpBlock | lftypeConsBlock) (equivConc _ _ _).
%total {SP} (equivConc _ SP _).

73
A.7 shiftSeq.elf
% Adam Poswolsky
% Encoding of Shift Property in Sequent Calculus

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Shifting:
% Namely, if Omega |-- (past T) then Omega |-- T
% and/or if Omega |-- T then (past Omega) |-- T
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% This captures the property that if we can prove something


% in the past, then you can also prove it is true in the present.
% There are a lot of "messy" details in this proof
% but is easily proved on paper.

% This proof proceeds in three steps.


% First, we create conc’ and show that we can copy from conc’ to conc.
% Second, we shift fron conc X T to conc’ (s X) T.
% Finally, we put the first two together to go from conc X T to conc (s X) T.

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% STEP 1 : Copy from a conc’ to conc
% Note that this system is identical except we added !! (to shift hyps)
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

hyp’ : nat -> pureO -> type. %name hyp’ H’ h’.


!! : hyp’ X TP -> hyp’ (s X) TP.

conc’ : nat -> o -> type. %name conc’ (D’ E’) (d’ e’).
exp’ : nat -> lftp -> type. %name exp’ (M’ N’) (m’ n’).

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% LF Level
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

lam’ : (exp’ X A -> exp’ X B) -> exp’ X (A arrow B).


app’ : exp’ X (A arrow B)-> exp’ X A -> exp’ X B.
shiftLF’ : exp’ X A -> exp’ (s X) A.
castHyp’ : hyp’ X (inj A) -> exp’ X A.

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Meta Level
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

axiom’ : le X Y -> hyp’ X TP -> conc’ Y (! TP).


impr’ : (hyp’ X TP1 -> conc’ X (! TP2))
-> conc’ X (! (TP1 imp TP2)).
impl’ : le X Y -> hyp’ X (TP1 imp TP2) -> conc’ Y (! TP1)
-> (hyp’ Y TP2 -> conc’ Y (! S)) -> conc’ Y (! S).
topr’ : conc’ _ (! top).
botl’ : le X Y -> hyp’ X bot -> conc’ Y (! TP).
pastr’ : conc’ X T -> conc’ (s X) (past T).
injr’ : exp’ X A -> conc’ X (! (inj A)).
pairr’ : conc’ X (! TP1) -> conc’ X (! TP2) -> conc’ X (! (pair TP1 TP2)).
pairl’ : le X Y -> hyp’ X (pair TP1 TP2)
-> (hyp’ Y TP1 -> hyp’ Y TP2 -> conc’ Y (! S))
-> conc’ Y (! S).

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Copying from conc’ to conc
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
copyLF’ : exp’ X A -> exp X A -> type. %name copyLF’ C c.
%mode copyLF’ +M’ -M.
copyC’ : conc’ X T -> conc X T -> type. %name copyC’ C c.
%mode copyC’ +D’ -D.
copyH’ : hyp’ Y TP -> le X Y -> hyp X TP -> type. %name copyH’ C c.
%mode copyH’ +H’ -L -H.

%block lfcopyBlock : some {Y:nat}{A:lftp} block {m:exp Y A}{n:exp’ Y A}{m:copyLF’ n m}.


%block copyBlock : some {Y:nat}{TP:pureO}
block {h:hyp Y TP} {h’:hyp’ Y TP} {m: copyH’ h’ base h}.

74
shiftLFGeneral : le X Y -> exp X A -> exp Y A -> type.
%mode shiftLFGeneral +L +M -M’.
shiftLFGeneralBase : shiftLFGeneral base M M.
shiftLFGeneralInd : shiftLFGeneral (one L) M (shiftLF M’)
<- shiftLFGeneral L M M’.
%worlds (copyBlock | lfcopyBlock | lftypeConsBlock ) (shiftLFGeneral _ _ _).
%total {L} (shiftLFGeneral L _ _).

copy-!!’ :copyH’ (!! H’) L’ H


<- copyH’ H’ L H
<- leAddOneRight L L’.

copyLF’lam : copyLF’ (lam’ M’) (lam M)


<- ({m}{m’} copyLF’ m’ m -> copyLF’ (M’ m’) (M m)).
copyLF’app : copyLF’ (app’ M1’ M2’) (app M1 M2)
<- copyLF’ M1’ M1
<- copyLF’ M2’ M2.
copyLF’shiftLF : copyLF’ (shiftLF’ M’) (shiftLF M)
<- copyLF’ M’ M.

copyLF’castHyp : copyLF’ (castHyp’ H’) M


<- copyH’ H’ L H
<- shiftLFGeneral L (castHyp H) M.

copyC’_axiom : copyC’ (axiom’ L1 H’) (axiom L3 H)


<- copyH’ H’ L2 H
<- leTrans L2 L1 L3.

copyC’_impr : copyC’ (impr’ D’) (impr D)


<- ({h}{h’} copyH’ h’ base h
-> copyC’ (D’ h’) (D h)).

copy-impl’: copyC’ (impl’ L1 H’ D1’ D2’) (impl L3 H D1 D2)


<- copyC’ D1’ D1
<- ({h} {h’} copyH’ h’ base h
-> copyC’ (D2’ h’) (D2 h))
<- copyH’ H’ L2 H
<- leTrans L2 L1 L3.

copyC’_topr : copyC’ topr’ topr.

copy-botl’ : copyC’ (botl’ L1 H’) (botl L3 H)


<- copyH’ H’ L2 H
<- leTrans L2 L1 L3.

copy-pastr’ : copyC’ (pastr’ D’) (pastr D)


<- copyC’ D’ D.

copy-injr’ : copyC’ (injr’ M’) (injr M)


<- copyLF’ M’ M.

copy-pairr’ : copyC’ (pairr’ D1’ D2’) (pairr D1 D2)


<- copyC’ D1’ D1
<- copyC’ D2’ D2.

copy-pairl’: copyC’ (pairl’ L1 H’ D’) (pairl L3 H D)


<- ({h} {h’} copyH’ h’ base h
-> ({h2} {h2’} copyH’ h2’ base h2
-> copyC’ (D’ h2’ h’) (D h2 h)))
<- copyH’ H’ L2 H
<- leTrans L2 L1 L3.

%worlds (copyBlock | lfcopyBlock | lftypeConsBlock )


(copyC’ _ _) (copyH’ _ _ _) (copyLF’ _ _).
%terminates (D’ H’ M’) (copyC’ D’ _) (copyH’ H’ _ _) (copyLF’ M’ _).
%covers (copyC’ +D’ -D) (copyH’ +H’ -L -H) (copyLF’ +M’ -M).
%total (D’ H’ M’) (copyC’ D’ _) (copyH’ H’ _ _) (copyLF’ M’ _).

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

75
% STEP 2
% Shifting conc Y T to conc’ (s Y) T
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

map’ : hyp X TP -> le X Y -> hyp’ (s Y) TP -> type. %name map’ W w.


%mode map’ +H +L -H’.

calcShiftLF’ : exp Y A -> exp’ (s Y) A -> type. %name calcShiftLF’ S s.


%mode calcShiftLF’ +M -M’.

shift’ : conc Y T -> conc’ (s Y) T -> type. %name shift’ S s.


%mode shift’ +D -D’.

%block lfmapBlock : some {Y:nat}{A:lftp}


block {m:exp Y A}{n:exp’ (s Y) A}{s:calcShiftLF’ m n}.
%block mapBlock : some {Y:nat}{TP:pureO}
block {h:hyp Y TP}{h’:hyp’ (s Y) TP}{s:map’ h base h’}.
%block lfmapcopyBlock : some {Y:nat}{A:lftp}
block {m:exp Y A}{n:exp’ Y A}{c:copyLF’ n m}{s:calcShiftLF’ m (shiftLF’ n)}.
%block mapcopyBlock : some {Y:nat}{TP:pureO}
block {h:hyp Y TP}{h’:hyp’ Y TP}{c:copyH’ h’ base h}{s:map’ h base (!! h’)}.

calcShiftLF’lam : calcShiftLF’ (lam M) (lam’ M’)


<- ({n}{n’} calcShiftLF’ n n’ -> calcShiftLF’ (M n) (M’ n’)).

calcShiftLF’app : calcShiftLF’ (app M1 M2) (app’ M1’ M2’)


<- calcShiftLF’ M1 M1’
<- calcShiftLF’ M2 M2’.

calcShiftLF’shiftLF : calcShiftLF’ (shiftLF M1) (shiftLF’ M1’)


<- calcShiftLF’ M1 M1’.

calcShiftLF’castHyp : calcShiftLF’ (castHyp H) (castHyp’ H’)


<- map’ H base H’.

map’_ind : map’ H (one L) (!! H’)


<- map’ H L H’.

shift’-axiom: shift’ (axiom L H) (axiom’ L’ H’)


<- map’ H base H’
<- leAddOneBoth L L’.

shift’-impr: shift’ (impr D) (impr’ D’)


<- ({h} {h’} map’ h base h’
-> shift’ (D h) (D’ h’)).

shift’-impl: shift’ (impl L H D1 D2) (impl’ L’ H’ D1’ D2’)


<- shift’ D1 D1’
<- ({h} {h’} map’ h base h’
-> shift’ (D2 h) (D2’ h’))
<- map’ H base H’
<- leAddOneBoth L L’.

shift’-topr : shift’ (topr) (topr’).

shift’-botl : shift’ (botl L H) (botl’ L’ H’)


<- map’ H base H’
<- leAddOneBoth L L’.

shift’-pastr : shift’ (pastr D) (pastr’ D’)


<- shift’ D D’.

shift’-injr : shift’ (injr M) (injr’ M’)


<- calcShiftLF’ M M’.

shift’-pairr : shift’ (pairr D1 D2) (pairr’ D1’ D2’)


<- shift’ D1 D1’
<- shift’ D2 D2’.

76
shift’-pairl: shift’ (pairl L H D) (pairl’ L’ H’ D’)
<- ({h} {h’} map’ h base h’
-> ({h2} {h2’} map’ h2 base h2’
-> shift’ (D h2 h) (D’ h2’ h’)))
<- map’ H base H’
<- leAddOneBoth L L’.

%worlds (mapBlock | mapcopyBlock | lfmapBlock | lfmapcopyBlock | lftypeConsBlock )


(shift’ _ _ ) (map’ _ _ _) (calcShiftLF’ _ _).
%terminates {H L} (map’ H L _).
%total {H L} (map’ H L _).
%terminates {M} (calcShiftLF’ M _).
%total {M} (calcShiftLF’ M _).
%terminates {D} (shift’ D _).
%total {D} (shift’ D _).

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Final Shift Stage : Put it together to get from conc Y A to conc (s Y) A
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

shift : conc Y T -> conc (s Y) T -> type.


%mode shift +D -D2.
shiftCase : shift D D2
<- shift’ D D’
<- copyC’ D’ D2.
%worlds (mapcopyBlock | lfmapcopyBlock | lftypeConsBlock) (shift _ _).
%terminates {D} (shift D _) .
%total {D} (shift D _).

shiftPast : conc Y (past T) -> conc Y T -> type.


%mode shiftPast +D -D2.

shiftPastPastr : shiftPast (pastr D) E


<- shift D E.

%worlds (mapcopyBlock | lfmapcopyBlock | lftypeConsBlock) (shiftPast _ _).


%terminates {D} (shiftPast D _) .
%covers (shiftPast +D -D2).
%total {D} (shiftPast D _).

shiftGeneral : le X Y -> conc X T -> conc Y T -> type.


%mode shiftGeneral +L +D -D2.
shiftGeneralBase : shiftGeneral base D D.
shiftGeneralInd : shiftGeneral (one L) D E
<- shiftGeneral L D D2
<- shift D2 E.
%worlds(mapcopyBlock | lfmapcopyBlock | lftypeConsBlock ) (shiftGeneral _ _ _).
%total {L} (shiftGeneral L _ _).

77
A.8 cutAdmis.elf
% Adam Poswolsky
% Encoding of Admissibility of Cut

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Admissibility of Cut:
% Namely, if Omega |-- T and Omega, T |-- S then Omega |-- S
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

ca : {T} conc X T -> stripPast X T Y TP -> (hyp Y TP -> conc X S) -> conc X S -> type.
caPure : {TP} conc X (! TP) -> (hyp X TP -> conc X S) -> conc X S -> type.

%mode (ca +T +D +SP +E -F).


%mode (caPure +TP +D +E -F).

% %%%%%%%%%%%%%%%%%%%%%
% Bridge ca and caPure
% %%%%%%%%%%%%%%%%%%%%%
ca_bridge : ca (! TP) D stripPastPure E F
<- caPure TP D E F.

% %%%%%%%%%%%%%%%%%%%%%
% Essential Conversions
% %%%%%%%%%%%%%%%%%%%%%

ca_axiom_r : ca T D SP ([h] axiom L h) F


<- equivConc D SP D’
<- shiftGeneral L D’ F.
caPure_axiom_r : caPure TP D ([h] axiom L h) D.

caPure_impl_r : caPure (TP1 imp TP2) (impr D) ([h] impl L h (E1 h) (E2 h)) F3
<- caPure (TP1 imp TP2) (impr D) E1 E1’
<- ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) ->
caPure (TP1 imp TP2) (impr D) ([h] E2 h h2) (E2’ h2))
<- caPure TP1 E1’ D F1
<- caPure TP2 F1 E2’ F3.

ca_pastr_l_pastr_r : ca (past T) (pastr D) (stripPastPast SP) ([h] pastr (E h)) (pastr F)


<- ca T D SP E F.

caPure_injr_r : caPure (inj A) (injr N) ([h] injr (M h)) (injr (M’ N))
<- convertHypExp M M’.

caPure_pairl_r : caPure (pair TP1 TP2) (pairr D1 D2) ([h] pairl L h (E h)) F*
<- ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’)
-> ({h3}{h3’} copyH’ h3’ base h3 -> map’ h3 base (!! h3’) ->
caPure (pair TP1 TP2) (pairr D1 D2) ([h] E h h2 h3) (E’ h2 h3)))
<- ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’)
-> caPure TP1 D1 ([h] E’ h h2) (F2 h2))
<- caPure TP2 D2 F2 F*.

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Shift on left.
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% If we have pastr on the left but not pastr on the right,
% then we shift the result on the left and call the IH.
%

ca_pastr_l1 : ca (past T) (pastr D) (stripPastPast SP) ([h] botl L h) F


<- shift D D’
<- stripAddOne SP SP’
<- stripToLess SP’ L’
<- ca T D’ SP’ ([h] botl L’ h) F.

ca_pastr_l2 : ca (past T) (pastr D) (stripPastPast SP) ([h] impl L h (E1 h) (E2 h)) F
<- ca (past T) (pastr D) (stripPastPast SP) E1 E1’
<- ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) ->
ca (past T) (pastr D) (stripPastPast SP) ([h] E2 h h2) (E2’ h2))
<- shift D D’
<- stripAddOne SP SP’
<- stripToLess SP’ L’

78
<- ca T D’ SP’ ([h] impl L’ h E1’ E2’) F.

ca_pastr_l3a : ca (past T) (pastr D) (stripPastPast (SP : stripPast X1 T X2 (inj B))) ([h] injr (M h)) F
<- shift D D’
<- stripAddOne SP SP’
<- stripToLess SP’ L’
<- convertHypExp M M’
<- shiftNegExpLF L’ M’ M’’
<- ca T D’ SP’ ([h] injr (([x] M’’ (castHyp x)) h)) F.

ca_pastr_l3b : ca (past T) (pastr D) (stripPastPast SP) ([h] injr (M h)) (injr N)


<- strengthenLFNI notInjTop M N.

ca_pastr_l3c : ca (past T) (pastr D) (stripPastPast SP) ([h] injr (M h)) (injr N)


<- strengthenLFNI notInjImp M N.

ca_pastr_l3d : ca (past T) (pastr D) (stripPastPast SP) ([h] injr (M h)) (injr N)


<- strengthenLFNI notInjBot M N.

ca_pastr_l3e : ca (past T) (pastr D) (stripPastPast SP) ([h] injr (M h)) (injr N)


<- strengthenLFNI notInjPair M N.

ca_pastr_l4 : ca (past T) (pastr D) (stripPastPast SP) ([h] pairl L h (E h)) F


<- ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) ->
({h3}{h3’} copyH’ h3’ base h3 -> map’ h3 base (!! h3’) ->
ca (past T) (pastr D) (stripPastPast SP) ([h] E h h2 h3) (E’ h2 h3)))
<- shift D D’
<- stripAddOne SP SP’
<- stripToLess SP’ L’
<- ca T D’ SP’ ([h] pairl L’ h E’) F.

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Commutative Conversions (on left)
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

caPure_axiom_l : caPure TP (axiom L H) E (E’ H)


<- weakenHyp L E E’.

caPure_impl_l : caPure TP (impl L H D1 D2) E (impl L H D1 F)


<- ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) ->
caPure TP (D2 h2) E (F h2)).

caPure_pairl_l : caPure TP (pairl L H D) E (pairl L H F)


<- ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) ->
({h3}{h3’} copyH’ h3’ base h3 -> map’ h3 base (!! h3’) ->
caPure TP (D h2 h3) E (F h2 h3))).

%{
% Here we need to take care of the case when we have botl on the left
% and an E of the form ([h] impl _ h _ _), ([h] pairl _ h _ _ _),
% or ([h] botl _ h _), or ([h] injr (M h))
}%
caPure_botl_l_impl_r1 : caPure _ (botl L H) ([h] impl L* h _ _) (botl L H).

caPure_botl_l_pairl_r1 : caPure _ (botl L H) ([h] pairl L* h _) (botl L H).

caPure_botl_l_botl_r : caPure _ (botl L H) ([h] botl L* h) (botl L H).


caPure_botl_l_injr_r : caPure _ (botl L H) ([h] injr _) (botl L H).

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Strengthening Conversion for past and inj
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Strengthen Away when Pastr is on the right and left is in present.


% Here D can be impr, topr, botl, injr, or pairr
% or impl or pairl

caPure_strengthenImprPastr1 : caPure _ (impr _) ([h] pastr (E’ h)) F


<- strengthenP ([h] pastr (E’ h)) F.
caPure_strengthenToprPastr2 : caPure _ (topr) ([h] pastr (E’ h)) F

79
<- strengthenP ([h] pastr (E’ h)) F.
caPure_strengthenBotlPastr3 : caPure _ (botl _ _) ([h] pastr (E’ h)) F
<- strengthenP ([h] pastr (E’ h)) F.
caPure_strengthenInjrPastr4 : caPure _ (injr _) ([h] pastr (E’ h)) F
<- strengthenP ([h] pastr (E’ h)) F.
caPure_strengthenInjrPastr5 : caPure _ (pairr _ _) ([h] pastr (E’ h)) F
<- strengthenP ([h] pastr (E’ h)) F.
caPure_strengthenInjrPastr6 : caPure _ (impl _ _ _ _) ([h] pastr (E’ h)) F
<- strengthenP ([h] pastr (E’ h)) F.
caPure_strengthenInjrPastr7 : caPure _ (pairl _ _ _) ([h] pastr (E’ h)) F
<- strengthenP ([h] pastr (E’ h)) F.

% Now for inject on right...


caPure_strengthen_ImprInjr : caPure _ (impr _) ([h] injr (M h)) (injr N)
<- strengthenLFNI notInjImp M N.
caPure_strengthen_TopInjr : caPure _ (topr) ([h] injr (M h)) (injr N)
<- strengthenLFNI notInjTop M N.
caPure_strengthen_PairrInjr : caPure _ (pairr _ _) ([h] injr (M h)) (injr N)
<- strengthenLFNI notInjPair M N.

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Commutative Conversions (on right)
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

ca_axiom_rCommute : ca T D SP ([h] axiom L H) (axiom L H).


caPure_axiom_rCommute : caPure TP D ([h] axiom L H) (axiom L H).

ca_topr_rCommute : ca T D SP ([h] topr) topr.


caPure_topr_rCommute : caPure TP D ([h] topr) topr.

ca_botl_rCommute : ca T D SP ([h] botl L H) (botl L H).


caPure_botl_rCommute : caPure TP D ([h] botl L H) (botl L H).

ca_impr_rCommute : ca T D SP ([h] impr (E h)) (impr F)


<- ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) ->
ca T D SP ([h] (E h h2)) (F h2)).
caPure_impr_rCommute : caPure TP D ([h] impr (E h)) (impr F)
<- ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) ->
caPure TP D ([h] (E h h2)) (F h2)).

ca_impl_rCommute : ca T D SP ([h] impl L H (E1 h) (E2 h)) (impl L H E1’ E2’)


<- ca T D SP E1 E1’
<- ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) ->
ca T D SP ([h] E2 h h2) (E2’ h2)).
caPure_impl_rCommute : caPure TP D ([h] impl L H (E1 h) (E2 h)) (impl L H E1’ E2’)
<- caPure TP D E1 E1’
<- ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) ->
caPure TP D ([h] E2 h h2) (E2’ h2)).

ca_pairr_rCommute : ca T D SP ([h] pairr (E1 h) (E2 h)) (pairr F1 F2)


<- ca T D SP E1 F1
<- ca T D SP E2 F2.
caPure_pairr_rCommute : caPure TP D ([h] pairr (E1 h) (E2 h)) (pairr F1 F2)
<- caPure TP D E1 F1
<- caPure TP D E2 F2.

ca_pairl_rCommute : ca T D SP ([h] pairl L H (E h)) (pairl L H E’)


<- ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) ->
({h3}{h3’} copyH’ h3’ base h3 -> map’ h3 base (!! h3’) ->
ca T D SP ([h] E h h2 h3) (E’ h2 h3))).
caPure_pairl_rCommute : caPure TP D ([h] pairl L H (E h)) (pairl L H E’)
<- ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) ->
({h3}{h3’} copyH’ h3’ base h3 -> map’ h3 base (!! h3’) ->
caPure TP D ([h] E h h2 h3) (E’ h2 h3))).

%worlds (mapcopyBlock | lfmapcopyBlock | lftypeConsBlock) (ca _ _ _ _ _) (caPure _ _ _ _).


%terminates {(T TP’) [(D D’) (E E’)]} (ca T D _ E _) (caPure TP’ D’ E’ _).
%covers (ca +T +D +SP +E -F) (caPure +TP +D +E -F).
%total {(T TP’) [(D D’) (E E’)]} (ca T D _ E _) (caPure TP’ D’ E’ _).

80
A.9 natDed.elf
% Adam Poswolsky
% Formulation of Natural Deduction version
% And some basic properties.

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Natural Deduction Meta Level
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
concND : nat -> o -> type. %name concND (D E F) (d e f).

botND : concND X (! bot) -> concND X (! TP).

%
% When introducing a function whose argument has type (inj A)
% we need to also introduce an (exp _ A) for use by the LF level.
% Therefore, when the argument is an (inj A), the natural extension
% would look like (concND X’ (inj AA) -> exp X’ AA -> concND X T)
% But this is no better than just (exp X’ AA -> concND X T), so
% we just use that.
%
MlamInj : (exp X A -> concND X (! TP2)) -> concND X (! ((inj A) imp TP2)).
MlamNI : notInj TP ->
(concND X (! TP) -> concND X (! TP2)) -> concND X (! (TP imp TP2)).

Mapp : concND X (!(TP1 imp TP2)) -> concND X (! TP1) -> concND X (! TP2).
topND : concND X (! top).
prev : concND X T -> concND (s X) (past T).
inject : exp X A -> concND X (!(inj A)).
pairI : concND X (! TP1) -> concND X (! TP2) -> concND X (! (pair TP1 TP2)).

% Similarly to the lam case, we need 4 cases for pairE to distinguish


% between inj and notInj
pairE00 : concND X (! (pair TP1 TP2))
-> notInj TP1 -> notInj TP2
-> (concND X (! TP1) -> concND X (! TP2) -> concND X (! S))
-> concND X (! S).
pairE01 : concND X (! (pair TP1 (inj B)))
-> notInj TP1
-> (concND X (! TP1) -> exp X B -> concND X (! S))
-> concND X (! S).
pairE10 : concND X (! (pair (inj A) TP2))
-> notInj TP2
-> (exp X A -> concND X (! TP2) -> concND X (! S))
-> concND X (! S).
pairE11 : concND X (! (pair (inj A) (inj B)))
-> (exp X A -> exp X B -> concND X (! S))
-> concND X (! S).

% Note that shift is an admissible rule from the others... it is trivial to prove on paper
% But we won’t go crazy again (see shiftSeq.elf) and prove it here.
shiftND : concND X T -> concND (s X) T.

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% BASIC PROPERTIES
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%block NDPureblock : some {X:nat}{TP:pureO}


block {d:concND X (! TP)}.

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Strengthening
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

81
strengthenFunND : notInj TP -> (hyp X TP -> concND X (! TP) -> concND Y T) -> (concND X (! TP) -> concND Y T) -> type.
%mode strengthenFunND +NI +F -F’.
strengthenFunND_BotND : strengthenFunND NI ([h][d] botND (D h d)) ([d] botND (D’ d))
<- strengthenFunND NI D D’.
strengthenFunND_MlamInj : strengthenFunND NI ([h][d] MlamInj (F h d)) ([d] MlamInj (F’ d))
<- ({n’} strengthenFunND NI ([h][d] F h d n’) ([d] F’ d n’)).
strengthenFunND_MlamNI : strengthenFunND NI ([h][d] MlamNI NI’ (F h d)) ([d] MlamNI NI’ (F’ d))
<- ({e} strengthenFunND NI ([h][d] F h d e) ([d] F’ d e)).

strengthenFunND_Mapp : strengthenFunND NI ([h][d] Mapp (D1 h d) (D2 h d)) ([d] Mapp (D1’ d) (D2’ d))
<- strengthenFunND NI D1 D1’
<- strengthenFunND NI D2 D2’.
strengthenFunND_TopND : strengthenFunND NI ([h][d] topND) ([d] topND).
strengthenFunND_Prev : strengthenFunND NI ([h][d] prev (D h d)) ([d] prev (D’ d))
<- strengthenFunND NI D D’.
strengthenFunND_Inject : strengthenFunND NI ([h][_] inject (M h)) ([d] inject M’)
<- strengthenLFNI NI M M’.

strengthenFunND_PairI : strengthenFunND NI ([h][d] pairI (D1 h d) (D2 h d)) ([d] pairI (D1’ d) (D2’ d))
<- strengthenFunND NI D1 D1’
<- strengthenFunND NI D2 D2’.

strengthenFunND_PairE00 : strengthenFunND NI ([h][d] pairE00 (D1 h d) NI1 NI2 (D2 h d))


([d] pairE00 (D1’ d) NI1 NI2 (D2’ d))
<- strengthenFunND NI D1 D1’
<- ({e1}{e2} strengthenFunND NI ([h][d] D2 h d e1 e2) ([d] D2’ d e1 e2)).

strengthenFunND_PairE01 : strengthenFunND NI ([h][d] pairE01 (D1 h d) NI1 (D2 h d))


([d] pairE01 (D1’ d) NI1 (D2’ d))
<- strengthenFunND NI D1 D1’
<- ({e1}{m2} strengthenFunND NI ([h][d] D2 h d e1 m2) ([d] D2’ d e1 m2)).

strengthenFunND_PairE10 : strengthenFunND NI ([h][d] pairE10 (D1 h d) NI2 (D2 h d))


([d] pairE10 (D1’ d) NI2 (D2’ d))
<- strengthenFunND NI D1 D1’
<- ({m1}{e2} strengthenFunND NI ([h][d] D2 h d m1 e2) ([d] D2’ d m1 e2)).

strengthenFunND_PairE11 : strengthenFunND NI ([h][d] pairE11 (D1 h d) (D2 h d))


([d] pairE11 (D1’ d) (D2’ d))
<- strengthenFunND NI D1 D1’
<- ({m1}{m2} strengthenFunND NI ([h][d] D2 h d m1 m2) ([d] D2’ d m1 m2)).

strengthenFunND_ShiftND : strengthenFunND NI ([h][d] shiftND (D h d)) ([d] shiftND (D’ d))


<- strengthenFunND NI D D’.
strengthenFunND_Block : strengthenFunND NI ([h][d] (D d)) ([d] D d).
%worlds (NDPureblock | hypBlock | lfexpBlock | lftypeConsBlock) (strengthenFunND _ _ _).
%total {F} (strengthenFunND _ F _).

% This is used when we encounter a case that is impossible


fromEmptyComesAllND : emptyType -> concND X T -> type.
%mode +{X:nat} +{T:o} +{EE:emptyType} -{D:concND X T} (fromEmptyComesAllND EE D).
%worlds (NDPureblock | hypBlock | lfexpBlock | lftypeConsBlock) (fromEmptyComesAllND _ _).
%total {EE} (fromEmptyComesAllND EE _).

strengthenND : le X Y -> (concND (s Y) (! TP) -> concND X T) -> concND X T -> type.
%mode strengthenND +L +F -F’.
strengthenND_BotND : strengthenND L ([d] botND (D d)) (botND D’)
<- strengthenND L D D’.
strengthenND_MlamInj : strengthenND L ([d] MlamInj (F d)) (MlamInj F’)
<- ({n’} strengthenND L ([d] F d n’) (F’ n’)).
strengthenND_MlamNI : strengthenND L ([d] MlamNI NI’ (F d)) (MlamNI NI’ F’)
<- ({e} strengthenND L ([d] F d e) (F’ e)).

strengthenND_Mapp : strengthenND L ([d] Mapp (D1 d) (D2 d)) (Mapp D1’ D2’)
<- strengthenND L D1 D1’
<- strengthenND L D2 D2’.
strengthenND_TopND : strengthenND L ([d] topND) (topND).
strengthenND_Prev : strengthenND L ([d] prev (D d)) (prev D’)
<- leRemoveOneLeft L L’
<- strengthenND L’ D D’.
strengthenND_Inject : strengthenND L ([_] inject M) (inject M).

strengthenND_PairI : strengthenND L ([d] pairI (D1 d) (D2 d)) (pairI D1’ D2’)
<- strengthenND L D1 D1’

82
<- strengthenND L D2 D2’.

strengthenND_PairE00 : strengthenND L ([d] pairE00 (D1 d) NI1 NI2 (D2 d))


(pairE00 D1’ NI1 NI2 D2’)
<- strengthenND L D1 D1’
<- ({e1}{e2} strengthenND L ([d] D2 d e1 e2) (D2’ e1 e2)).

strengthenND_PairE01 : strengthenND L ([d] pairE01 (D1 d) NI1 (D2 d))


(pairE01 D1’ NI1 D2’)
<- strengthenND L D1 D1’
<- ({e1}{m2} strengthenND L ([d] D2 d e1 m2) (D2’ e1 m2)).

strengthenND_PairE10 : strengthenND L ([d] pairE10 (D1 d) NI2 (D2 d))


(pairE10 D1’ NI2 D2’)
<- strengthenND L D1 D1’
<- ({m1}{e2} strengthenND L ([d] D2 d m1 e2) (D2’ m1 e2)).

strengthenND_PairE11 : strengthenND L ([d] pairE11 (D1 d) (D2 d))


(pairE11 D1’ D2’)
<- strengthenND L D1 D1’
<- ({m1}{m2} strengthenND L ([d] D2 d m1 m2) (D2’ m1 m2)).

strengthenND_ShiftND : strengthenND L ([d] shiftND (D d)) (shiftND D’)


<- leRemoveOneLeft L L’
<- strengthenND L’ D D’.

strengthenND_Impossible : strengthenND (L: le (s X) X) F D


<- impossibleLessNum _ L EE
<- fromEmptyComesAllND EE D.

strengthenND_Block : strengthenND L ([d] D) D.

%worlds (NDPureblock | hypBlock | lfexpBlock | lftypeConsBlock) (strengthenND _ _ _).


%total {F} (strengthenND _ F _).

strengthenFunNDLF : (hyp X (inj A) -> exp X A -> concND Y T) -> (exp X A -> concND Y T) -> type.
%mode strengthenFunNDLF +F -F’.
strengthenFunNDLF_BotND : strengthenFunNDLF ([h][n] botND (D h n)) ([n] botND (D’ n))
<- strengthenFunNDLF D D’.
strengthenFunNDLF_MlamInj : strengthenFunNDLF ([h][n] MlamInj (F h n)) ([n] MlamInj (F’ n))
<- ({n’} strengthenFunNDLF ([h][n] F h n n’) ([n] F’ n n’)).
strengthenFunNDLF_MlamNI : strengthenFunNDLF ([h][n] MlamNI NI (F h n)) ([n] MlamNI NI (F’ n))
<- ({e} strengthenFunNDLF ([h][n] F h n e) ([n] F’ n e)).

strengthenFunNDLF_Mapp : strengthenFunNDLF ([h][n] Mapp (D1 h n) (D2 h n)) ([n] Mapp (D1’ n) (D2’ n))
<- strengthenFunNDLF D1 D1’
<- strengthenFunNDLF D2 D2’.
strengthenFunNDLF_TopND : strengthenFunNDLF ([h][n] topND) ([n] topND).
strengthenFunNDLF_Prev : strengthenFunNDLF ([h][n] prev (D h n)) ([n] prev (D’ n))
<- strengthenFunNDLF D D’.
strengthenFunNDLF_Inject : strengthenFunNDLF ([h][n] inject (M h n)) ([n] inject (([n’] M’ n’ n’) n))
<- ({n} convertHypExp ([h] M h n) (M’ n)).

strengthenFunNDLF_PairI : strengthenFunNDLF ([h][n] pairI (D1 h n) (D2 h n)) ([n] pairI (D1’ n) (D2’ n))
<- strengthenFunNDLF D1 D1’
<- strengthenFunNDLF D2 D2’.

strengthenFunNDLF_PairE00 : strengthenFunNDLF ([h][n] pairE00 (D1 h n) NI1 NI2 (D2 h n))


([n] pairE00 (D1’ n) NI1 NI2 (D2’ n))
<- strengthenFunNDLF D1 D1’
<- ({e1}{e2} strengthenFunNDLF ([h][n] D2 h n e1 e2) ([n] D2’ n e1 e2)).

strengthenFunNDLF_PairE01 : strengthenFunNDLF ([h][n] pairE01 (D1 h n) NI1 (D2 h n))


([n] pairE01 (D1’ n) NI1 (D2’ n))
<- strengthenFunNDLF D1 D1’
<- ({e1}{m2} strengthenFunNDLF ([h][n] D2 h n e1 m2) ([n] D2’ n e1 m2)).

strengthenFunNDLF_PairE10 : strengthenFunNDLF ([h][n] pairE10 (D1 h n) NI2 (D2 h n))


([n] pairE10 (D1’ n) NI2 (D2’ n))
<- strengthenFunNDLF D1 D1’
<- ({m1}{e2} strengthenFunNDLF ([h][n] D2 h n m1 e2) ([n] D2’ n m1 e2)).

strengthenFunNDLF_PairE11 : strengthenFunNDLF ([h][n] pairE11 (D1 h n) (D2 h n))


([n] pairE11 (D1’ n) (D2’ n))
<- strengthenFunNDLF D1 D1’

83
<- ({m1}{m2} strengthenFunNDLF ([h][n] D2 h n m1 m2) ([n] D2’ n m1 m2)).

strengthenFunNDLF_ShiftND : strengthenFunNDLF ([h][n] shiftND (D h n)) ([n] shiftND (D’ n))


<- strengthenFunNDLF D D’.
strengthenFunNDLF_Block : strengthenFunNDLF ([h][n] D) ([n] D).
%worlds (NDPureblock | hypBlock | lfexpBlock | lftypeConsBlock) (strengthenFunNDLF _ _).
%total {F} (strengthenFunNDLF F _).

strengthenNDLF : le X Y -> (exp (s Y) A -> concND X T) -> concND X T -> type.


%mode strengthenNDLF +L +F -D.
strengthenNDLF_botND : strengthenNDLF L ([n] botND (D n)) (botND D’)
<- strengthenNDLF L D D’.

strengthenNDLF_MlamInj : strengthenNDLF L ([n] MlamInj (F n)) (MlamInj F’)


<- ({m}
strengthenNDLF L ([n] F n m) (F’ m)).

strengthenNDLF_Mlam : strengthenNDLF L ([n] MlamNI NI (F n)) (MlamNI NI F’)


<- ({e}
strengthenNDLF L ([n] F n e) (F’ e)).

strengthenNDLF_Mapp : strengthenNDLF L ([n] Mapp (D1 n) (D2 n)) (Mapp D1’ D2’)
<- strengthenNDLF L D1 D1’
<- strengthenNDLF L D2 D2’.

strengthenNDLF_topND : strengthenNDLF L ([n] topND) topND.


strengthenNDLF_prev : strengthenNDLF L ([n] prev (D n)) (prev D’)
<- leRemoveOneLeft L L’
<- strengthenNDLF L’ D D’.
strengthenNDLF_inject : strengthenNDLF L ([n] inject (M n)) (inject M’)
<- strengthenLF2 L M M’.

strengthenNDLF_PairI : strengthenNDLF L ([n] pairI (D1 n) (D2 n)) (pairI D1’ D2’)
<- strengthenNDLF L D1 D1’
<- strengthenNDLF L D2 D2’.

strengthenNDLF_PairE00 : strengthenNDLF L ([n] pairE00 (D1 n) NI1 NI2 (D2 n))


(pairE00 D1’ NI1 NI2 D2’)
<- strengthenNDLF L D1 D1’
<- ({e1}{e2} strengthenNDLF L ([n] D2 n e1 e2) (D2’ e1 e2)).

strengthenNDLF_PairE01 : strengthenNDLF L ([n] pairE01 (D1 n) NI1 (D2 n))


(pairE01 D1’ NI1 D2’)
<- strengthenNDLF L D1 D1’
<- ({e1}{m2} strengthenNDLF L ([n] D2 n e1 m2) (D2’ e1 m2)).

strengthenNDLF_PairE10 : strengthenNDLF L ([n] pairE10 (D1 n) NI2 (D2 n))


(pairE10 D1’ NI2 D2’)
<- strengthenNDLF L D1 D1’
<- ({m1}{e2} strengthenNDLF L ([n] D2 n m1 e2) (D2’ m1 e2)).

strengthenNDLF_PairE11 : strengthenNDLF L ([n] pairE11 (D1 n) (D2 n))


(pairE11 D1’ D2’)
<- strengthenNDLF L D1 D1’
<- ({m1}{m2} strengthenNDLF L ([n] D2 n m1 m2) (D2’ m1 m2)).

strengthenNDLF_shiftND : strengthenNDLF L ([n] shiftND (D n)) (shiftND D’)


<- leRemoveOneLeft L L’
<- strengthenNDLF L’ D D’.

strengthenNDLF_block : strengthenNDLF L ([n] E) E.


%worlds (NDPureblock | hypBlock | lfexpBlock | lftypeConsBlock) (strengthenNDLF _ _ _).
%total {F} (strengthenNDLF _ F _).

futureRuleND : concND (s X) (past T) -> concND X T -> type.


%mode futureRuleND +D -D’.

futureRuleND_Prev : futureRuleND (prev D) D.

futureRuleND_ShiftND : futureRuleND (shiftND D) (shiftND D’)


<- futureRuleND D D’.

84
%worlds (NDPureblock | hypBlock | lfexpBlock | lftypeConsBlock) (futureRuleND _ _).
%total {D} (futureRuleND D _).

strengthenNDpast : (concND X (! TP) -> concND X (past T)) -> concND X (past T) -> type.
%mode strengthenNDpast +D -D’.
strengthenNDpastcase : strengthenNDpast D (prev E’)
<- ({e} futureRuleND (D e) (D’ e))
<- strengthenND base D’ E’.

%worlds (NDPureblock | hypBlock | lfexpBlock | lftypeConsBlock) (strengthenNDpast _ _).


%covers (strengthenNDpast +D -D’).
%total {D} (strengthenNDpast D _).

strengthenNDLFpast : (exp X A -> concND X (past T)) -> concND X (past T) -> type.
%mode strengthenNDLFpast +D -D’.
strengthenNDLFpastcase : strengthenNDLFpast D (prev E’)
<- ({m} futureRuleND (D m) (D’ m))
<- strengthenNDLF base D’ E’.

%worlds (NDPureblock | hypBlock | lfexpBlock | lftypeConsBlock) (strengthenNDLFpast _ _).


%covers (strengthenNDLFpast +D -D’).
%total {D} (strengthenNDLFpast D _).

85
A.10 natToSeq.elf
% Adam Poswolsky
% Conversion from Natural Deduction to Sequent Calculus.

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Convert Natural Deduction to Sequent Calculus
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
NDtoSQ : concND X T -> conc X T -> type.
%mode NDtoSQ +DN -D.

%block NDtoSQblockNI : some {X:nat}{TP:pureO}{NI:notInj TP}


block {h:hyp X TP}{h’:hyp’ X TP}{c:copyH’ h’ base h}{m:map’ h base (!! h’)}
{e:concND X (! TP)}{w:NDtoSQ e (axiom base h)}.
%block NDtoSQblockInj : some {X:nat}{A:lftp}
block {h:hyp X (inj A)}{h’:hyp’ X (inj A)}{c:copyH’ h’ base h}{m:map’ h base (!! h’)}
{m:exp X A}{n:exp’ X A}{w:copyLF’ n m}{s:calcShiftLF’ m (shiftLF’ n)}.

% %%%%%%%%%%%%%%%%%%%
% Meta Level
% %%%%%%%%%%%%%%%%%%%

NDtoSQ_botND : NDtoSQ (botND D) F


<- NDtoSQ D D’
<- ca (! bot) D’ stripPastPure ([h] botl base h) F.

NDtoSQ_MlamNI : NDtoSQ (MlamNI NI D) (impr D’)


<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’)
-> {e}(NDtoSQ e (axiom base h))
-> NDtoSQ (D e) (D’ h)).

NDtoSQ_MlamInj : NDtoSQ (MlamInj D) (impr ([h] D’ h (castHyp h)))


<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’)
-> {n}{n’} copyLF’ n’ n -> calcShiftLF’ n (shiftLF’ n’)
-> NDtoSQ (D n) (D’ h n)).

NDtoSQ_Mapp : NDtoSQ (Mapp E D) F


<- NDtoSQ E E’
<- NDtoSQ D D’
<- ca _ E’ stripPastPure ([h] impl base h D’ ([h’] axiom base h’)) F.

NDtoSQ_topND : NDtoSQ topND topr.


NDtoSQ_prev : NDtoSQ (prev D) (pastr D’)
<- NDtoSQ D D’.
NDtoSQ_inject : NDtoSQ (inject M) (injr M).

NDtoSQ_pairI : NDtoSQ (pairI D1 D2) (pairr D1’ D2’)


<- NDtoSQ D1 D1’
<- NDtoSQ D2 D2’.

NDtoSQ_pairE00 : NDtoSQ (pairE00 D1 NI1 NI2 D2) F


<- NDtoSQ D1 D1’
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {e}(NDtoSQ e (axiom base h))
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {e2}(NDtoSQ e2 (axiom base h2))
-> NDtoSQ (D2 e e2) (D2’ h h2)))
<- ca _ D1’ stripPastPure ([h] pairl base h D2’) F.

NDtoSQ_pairE01 : NDtoSQ (pairE01 D1 NI1 D2) F


<- NDtoSQ D1 D1’
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {e}(NDtoSQ e (axiom base h))
-> ({h2: hyp X (inj A)}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {n2}{n2’} copyLF’ n2’ n2 -> calcShiftLF’ n2 (shiftLF’ n2’)
-> NDtoSQ (D2 e n2) (D2’ h h2 n2)))
<- ca _ D1’ stripPastPure ([h] pairl base h ([h1][h2] D2’ h1 h2 (castHyp h2))) F.

NDtoSQ_pairE10 : NDtoSQ (pairE10 D1 NI2 D2) F


<- NDtoSQ D1 D1’
<- ({h: hyp X (inj A)}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {n}{n’} copyLF’ n’ n -> calcShiftLF’ n (shiftLF’ n’)
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {e2}(NDtoSQ e2 (axiom base h2))
-> NDtoSQ (D2 n e2) (D2’ h n h2)))
<- ca _ D1’ stripPastPure ([h] pairl base h ([h1][h2] D2’ h1 (castHyp h1) h2)) F.

NDtoSQ_pairE11 : NDtoSQ (pairE11 D1 D2) F


<- NDtoSQ D1 D1’
<- ({h: hyp X (inj A)}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {n}{n’} copyLF’ n’ n -> calcShiftLF’ n (shiftLF’ n’)
-> ({h2: hyp X (inj B)}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {n2}{n2’} copyLF’ n2’ n2 -> calcShiftLF’ n2 (shiftLF’ n2’)

86
-> NDtoSQ (D2 n n2) (D2’ h n h2 n2)))
<- ca _ D1’ stripPastPure ([h] pairl base h ([h1][h2] D2’ h1 (castHyp h1) h2 (castHyp h2))) F.

NDtoSQ_shift : NDtoSQ (shiftND D) D’’


<- NDtoSQ D D’
<- shift D’ D’’.

%worlds (NDtoSQblockNI | NDtoSQblockInj | lftypeConsBlock) (NDtoSQ _ _).


%terminates {DN} (NDtoSQ DN _).
%total {DN} (NDtoSQ DN _).

87
A.11 seqToNat.elf
% Adam Poswolsky
% Conversion from Sequent Calculus to Natural Deduction

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% First, a property we need when converting Sequent to Natural Deduction
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
NDprop : concND X (!(inj A)) -> (exp X A -> concND X T) -> concND X T -> type.
%mode NDprop +D +F -D’.
NDprop_pure : NDprop D E (Mapp (MlamInj E) D).
NDprop_impure : NDprop D E F
<- strengthenNDLFpast E F.
%worlds (hypBlock | lfexpBlock | NDPureblock | lftypeConsBlock) (NDprop _ _ _).
%terminates {F} (NDprop _ F _).
%total {F} (NDprop _ F _).

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Now Convert Sequent Calculus to Natural Deduction
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

SQtoND : conc X T -> concND X T -> type.


hypToCN : le X Y -> hyp X TP -> concND Y (! TP) -> type.

%mode SQtoND +D -DN.


%mode hypToCN +L +H -CN.

%block SQtoNDblockNI : some {X:nat}{TP:pureO}{NI:notInj TP}


block {h:hyp X TP}{h’:hyp’ X TP}{c:copyH’ h’ base h}{m:map’ h base (!! h’)}
{e:concND X (! TP)}{w:SQtoND (axiom base h) e}
{z:hypToCN base h e}.

%block SQtoNDblockInj : some {X:nat}{A:lftp}


block {h:hyp X (inj A)}{h’:hyp’ X (inj A)}
{c:copyH’ h’ base h}{m:map’ h base (!! h’)}
{m:exp X A}{n:exp’ X A}{w:copyLF’ n m}
{s:calcShiftLF’ m (shiftLF’ n)}{z:hypToCN base h (inject m)}.

hypToCN_Ind : hypToCN (one L) H (shiftND D)


<- hypToCN L H D.

%worlds (SQtoNDblockNI | SQtoNDblockInj | lftypeConsBlock) (hypToCN _ _ _).


%terminates {L} (hypToCN L _ _).
%total {L} (hypToCN L _ _).

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Meta Cases
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

SQtoND_axiom : SQtoND (axiom L H) F


<- hypToCN L H F.

SQtoND_imprTop : SQtoND (impr F) (MlamNI notInjTop F*)


<- ({h:hyp _ top}{h’} copyH’ h’ base h -> map’ h base (!! h’) ->
{e} SQtoND (axiom base h) e -> hypToCN base h e ->
SQtoND (F h) (F’ h e))
<- strengthenFunND notInjTop F’ F*.

SQtoND_imprTop : SQtoND (impr F) (MlamNI notInjTop F*)


<- ({h:hyp _ top}{h’} copyH’ h’ base h -> map’ h base (!! h’) ->
{e} SQtoND (axiom base h) e -> hypToCN base h e ->
SQtoND (F h) (F’ h e))
<- strengthenFunND notInjTop F’ F*.
SQtoND_imprBot : SQtoND (impr F) (MlamNI notInjBot F*)
<- ({h:hyp _ bot}{h’} copyH’ h’ base h -> map’ h base (!! h’) ->
{e} SQtoND (axiom base h) e -> hypToCN base h e ->
SQtoND (F h) (F’ h e))
<- strengthenFunND notInjBot F’ F*.
SQtoND_imprImp : SQtoND (impr F) (MlamNI notInjImp F*)
<- ({h:hyp _ (TP1 imp TP2)}{h’} copyH’ h’ base h -> map’ h base (!! h’) ->
{e} SQtoND (axiom base h) e -> hypToCN base h e ->
SQtoND (F h) (F’ h e))

88
<- strengthenFunND notInjImp F’ F*.

SQtoND_imprPair : SQtoND (impr F) (MlamNI notInjPair F*)


<- ({h:hyp _ (pair TP1 TP2)}{h’} copyH’ h’ base h -> map’ h base (!! h’) ->
{e} SQtoND (axiom base h) e -> hypToCN base h e ->
SQtoND (F h) (F’ h e))
<- strengthenFunND notInjPair F’ F*.

SQtoND_imprInj : SQtoND (impr F) (MlamInj F*)


<- ({h:hyp _ (inj A)}{h’} copyH’ h’ base h -> map’ h base (!! h’) ->
{m} {n} copyLF’ n m -> calcShiftLF’ m (shiftLF’ n) -> hypToCN base h (inject m) ->
SQtoND (F h) (F’ h m))
<- strengthenFunNDLF F’ F*.

SQtoND_implTop : SQtoND (impl L H D1 D2) (F2’ (Mapp F0 F1))


<- hypToCN L H F0
<- SQtoND D1 F1
<- ({h:hyp _ top}{h’} copyH’ h’ base h -> map’ h base (!! h’) ->
{e} SQtoND (axiom base h) e -> hypToCN base h e ->
SQtoND (D2 h) (F2 h e))
<- strengthenFunND notInjTop F2 F2’.
SQtoND_implBot : SQtoND (impl L H D1 D2) (F2’ (Mapp F00 F1))
<- hypToCN L H F00
<- SQtoND D1 F1
<- ({h:hyp _ bot}{h’} copyH’ h’ base h -> map’ h base (!! h’) ->
{e} SQtoND (axiom base h) e -> hypToCN base h e ->
SQtoND (D2 h) (F2 h e))
<- strengthenFunND notInjBot F2 F2’.

SQtoND_implImp : SQtoND (impl L H D1 D2) (F2’ (Mapp F00 F1))


<- hypToCN L H F00
<- SQtoND D1 F1
<- ({h:hyp _ (TP1 imp TP2)}{h’} copyH’ h’ base h -> map’ h base (!! h’) ->
{e} SQtoND (axiom base h) e -> hypToCN base h e ->
SQtoND (D2 h) (F2 h e))
<- strengthenFunND notInjImp F2 F2’.

SQtoND_implPair : SQtoND (impl L H D1 D2) (F2’ (Mapp F00 F1))


<- hypToCN L H F00
<- SQtoND D1 F1
<- ({h:hyp _ (pair TP1 TP2)}{h’} copyH’ h’ base h -> map’ h base (!! h’) ->
{e} SQtoND (axiom base h) e -> hypToCN base h e ->
SQtoND (D2 h) (F2 h e))
<- strengthenFunND notInjPair F2 F2’.

SQtoND_implInj : SQtoND (impl L H D1 D2) E


<- hypToCN L H F00
<- SQtoND D1 F1
<- ({h:hyp _ (inj A)}{h’} copyH’ h’ base h -> map’ h base (!! h’) ->
{m} {n} copyLF’ n m -> calcShiftLF’ m (shiftLF’ n)
-> hypToCN base h (inject m) ->
SQtoND (D2 h) (F2 h m))
<- strengthenFunNDLF F2 F2’
<- NDprop (Mapp F00 F1) F2’ E.

SQtoND_topr : SQtoND topr topND.

SQtoND_botl : SQtoND (botl L H) (botND D)


<- hypToCN L H D.

SQtoND_pastr : SQtoND (pastr D) (prev D’)


<- SQtoND D D’.

SQtoND_injr : SQtoND (injr M) (inject M).

SQtoND_pairr : SQtoND (pairr D1 D2) (pairI D1’ D2’)


<- SQtoND D1 D1’
<- SQtoND D2 D2’.

% We have 25 cases for pairl


% For convention we will use 0=top,1=bot,2=imp,3=pair,4=inj
% And we will label each case with XY where X is
% the type of the first element and Y is the type
% of the second.

89
SQtoND_pairl00 : SQtoND (pairl L H D) (pairE00 F00 notInjTop notInjTop F3)
<- hypToCN L H F00
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {e} SQtoND (axiom base h) e -> hypToCN base h e
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {e2} SQtoND (axiom base h2) e2 -> hypToCN base h2 e2 ->
SQtoND (D h h2) (F h e h2 e2)))
<- ({h}{e} strengthenFunND notInjTop (F h e) (F2 h e))
<- ({e2} strengthenFunND notInjTop ([h][e] F2 h e e2) ([e] F3 e e2)).

SQtoND_pairl01 : SQtoND (pairl L H D) (pairE00 F00 notInjTop notInjBot F3)


<- hypToCN L H F00
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {e} SQtoND (axiom base h) e -> hypToCN base h e
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {e2} SQtoND (axiom base h2) e2 -> hypToCN base h2 e2 ->
SQtoND (D h h2) (F h e h2 e2)))
<- ({h}{e} strengthenFunND notInjBot (F h e) (F2 h e))
<- ({e2} strengthenFunND notInjTop ([h][e] F2 h e e2) ([e] F3 e e2)).

SQtoND_pairl02 : SQtoND (pairl L H D) (pairE00 F00 notInjTop notInjImp F3)


<- hypToCN L H F00
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {e} SQtoND (axiom base h) e -> hypToCN base h e
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {e2} SQtoND (axiom base h2) e2 -> hypToCN base h2 e2 ->
SQtoND (D h h2) (F h e h2 e2)))
<- ({h}{e} strengthenFunND notInjImp (F h e) (F2 h e))
<- ({e2} strengthenFunND notInjTop ([h][e] F2 h e e2) ([e] F3 e e2)).

SQtoND_pairl03 : SQtoND (pairl L H D) (pairE00 F00 notInjTop notInjPair F3)


<- hypToCN L H F00
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {e} SQtoND (axiom base h) e -> hypToCN base h e
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {e2} SQtoND (axiom base h2) e2 -> hypToCN base h2 e2 ->
SQtoND (D h h2) (F h e h2 e2)))
<- ({h}{e} strengthenFunND notInjPair (F h e) (F2 h e))
<- ({e2} strengthenFunND notInjTop ([h][e] F2 h e e2) ([e] F3 e e2)).

SQtoND_pairl04 : SQtoND (pairl L H D) (pairE01 F00 notInjTop F3)


<- hypToCN L H F00
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {e} SQtoND (axiom base h) e -> hypToCN base h e
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {m2} {n2} copyLF’ n2 m2
-> calcShiftLF’ m2 (shiftLF’ n2) -> hypToCN base h2 (inject m2) -> SQtoND (D h h2) (F h e h2 m2)))
<- ({h}{e} strengthenFunNDLF (F h e) (F2 h e))
<- ({m2} strengthenFunND notInjTop ([h][e] F2 h e m2) ([e] F3 e m2)).

SQtoND_pairl10 : SQtoND (pairl L H D) (pairE00 F00 notInjBot notInjTop F3)


<- hypToCN L H F00
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {e} SQtoND (axiom base h) e -> hypToCN base h e
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {e2} SQtoND (axiom base h2) e2 -> hypToCN base h2 e2 ->
SQtoND (D h h2) (F h e h2 e2)))
<- ({h}{e} strengthenFunND notInjTop (F h e) (F2 h e))
<- ({e2} strengthenFunND notInjBot ([h][e] F2 h e e2) ([e] F3 e e2)).

SQtoND_pairl11 : SQtoND (pairl L H D) (pairE00 F00 notInjBot notInjBot F3)


<- hypToCN L H F00
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {e} SQtoND (axiom base h) e -> hypToCN base h e
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {e2} SQtoND (axiom base h2) e2 -> hypToCN base h2 e2 ->
SQtoND (D h h2) (F h e h2 e2)))
<- ({h}{e} strengthenFunND notInjBot (F h e) (F2 h e))
<- ({e2} strengthenFunND notInjBot ([h][e] F2 h e e2) ([e] F3 e e2)).

SQtoND_pairl12 : SQtoND (pairl L H D) (pairE00 F00 notInjBot notInjImp F3)


<- hypToCN L H F00
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {e} SQtoND (axiom base h) e -> hypToCN base h e
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {e2} SQtoND (axiom base h2) e2 -> hypToCN base h2 e2 ->
SQtoND (D h h2) (F h e h2 e2)))
<- ({h}{e} strengthenFunND notInjImp (F h e) (F2 h e))
<- ({e2} strengthenFunND notInjBot ([h][e] F2 h e e2) ([e] F3 e e2)).

SQtoND_pairl13 : SQtoND (pairl L H D) (pairE00 F00 notInjBot notInjPair F3)


<- hypToCN L H F00
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {e} SQtoND (axiom base h) e -> hypToCN base h e
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {e2} SQtoND (axiom base h2) e2 -> hypToCN base h2 e2 ->
SQtoND (D h h2) (F h e h2 e2)))
<- ({h}{e} strengthenFunND notInjPair (F h e) (F2 h e))
<- ({e2} strengthenFunND notInjBot ([h][e] F2 h e e2) ([e] F3 e e2)).

SQtoND_pairl14 : SQtoND (pairl L H D) (pairE01 F00 notInjBot F3)


<- hypToCN L H F00
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {e} SQtoND (axiom base h) e -> hypToCN base h e
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {m2} {n2} copyLF’ n2 m2

90
-> calcShiftLF’ m2 (shiftLF’ n2) -> hypToCN base h2 (inject m2) -> SQtoND (D h h2) (F h e h2 m2)))
<- ({h}{e} strengthenFunNDLF (F h e) (F2 h e))
<- ({m2} strengthenFunND notInjBot ([h][e] F2 h e m2) ([e] F3 e m2)).

SQtoND_pairl20 : SQtoND (pairl L H D) (pairE00 F00 notInjImp notInjTop F3)


<- hypToCN L H F00
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {e} SQtoND (axiom base h) e -> hypToCN base h e
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {e2} SQtoND (axiom base h2) e2 -> hypToCN base h2 e2 ->
SQtoND (D h h2) (F h e h2 e2)))
<- ({h}{e} strengthenFunND notInjTop (F h e) (F2 h e))
<- ({e2} strengthenFunND notInjImp ([h][e] F2 h e e2) ([e] F3 e e2)).

SQtoND_pairl21 : SQtoND (pairl L H D) (pairE00 F00 notInjImp notInjBot F3)


<- hypToCN L H F00
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {e} SQtoND (axiom base h) e -> hypToCN base h e
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {e2} SQtoND (axiom base h2) e2 -> hypToCN base h2 e2 ->
SQtoND (D h h2) (F h e h2 e2)))
<- ({h}{e} strengthenFunND notInjBot (F h e) (F2 h e))
<- ({e2} strengthenFunND notInjImp ([h][e] F2 h e e2) ([e] F3 e e2)).

SQtoND_pairl22 : SQtoND (pairl L H D) (pairE00 F00 notInjImp notInjImp F3)


<- hypToCN L H F00
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {e} SQtoND (axiom base h) e -> hypToCN base h e
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {e2} SQtoND (axiom base h2) e2 -> hypToCN base h2 e2 ->
SQtoND (D h h2) (F h e h2 e2)))
<- ({h}{e} strengthenFunND notInjImp (F h e) (F2 h e))
<- ({e2} strengthenFunND notInjImp ([h][e] F2 h e e2) ([e] F3 e e2)).

SQtoND_pairl23 : SQtoND (pairl L H D) (pairE00 F00 notInjImp notInjPair F3)


<- hypToCN L H F00
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {e} SQtoND (axiom base h) e -> hypToCN base h e
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {e2} SQtoND (axiom base h2) e2 -> hypToCN base h2 e2 ->
SQtoND (D h h2) (F h e h2 e2)))
<- ({h}{e} strengthenFunND notInjPair (F h e) (F2 h e))
<- ({e2} strengthenFunND notInjImp ([h][e] F2 h e e2) ([e] F3 e e2)).

SQtoND_pairl24 : SQtoND (pairl L H D) (pairE01 F00 notInjImp F3)


<- hypToCN L H F00
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {e} SQtoND (axiom base h) e -> hypToCN base h e
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {m2} {n2} copyLF’ n2 m2
-> calcShiftLF’ m2 (shiftLF’ n2) -> hypToCN base h2 (inject m2) -> SQtoND (D h h2) (F h e h2 m2)))
<- ({h}{e} strengthenFunNDLF (F h e) (F2 h e))
<- ({m2} strengthenFunND notInjImp ([h][e] F2 h e m2) ([e] F3 e m2)).

SQtoND_pairl30 : SQtoND (pairl L H D) (pairE00 F00 notInjPair notInjTop F3)


<- hypToCN L H F00
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {e} SQtoND (axiom base h) e -> hypToCN base h e
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {e2} SQtoND (axiom base h2) e2 -> hypToCN base h2 e2 ->
SQtoND (D h h2) (F h e h2 e2)))
<- ({h}{e} strengthenFunND notInjTop (F h e) (F2 h e))
<- ({e2} strengthenFunND notInjPair ([h][e] F2 h e e2) ([e] F3 e e2)).

SQtoND_pairl31 : SQtoND (pairl L H D) (pairE00 F00 notInjPair notInjBot F3)


<- hypToCN L H F00
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {e} SQtoND (axiom base h) e -> hypToCN base h e
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {e2} SQtoND (axiom base h2) e2 -> hypToCN base h2 e2 ->
SQtoND (D h h2) (F h e h2 e2)))
<- ({h}{e} strengthenFunND notInjBot (F h e) (F2 h e))
<- ({e2} strengthenFunND notInjPair ([h][e] F2 h e e2) ([e] F3 e e2)).

SQtoND_pairl32 : SQtoND (pairl L H D) (pairE00 F00 notInjPair notInjImp F3)


<- hypToCN L H F00
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {e} SQtoND (axiom base h) e -> hypToCN base h e
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {e2} SQtoND (axiom base h2) e2 -> hypToCN base h2 e2 ->
SQtoND (D h h2) (F h e h2 e2)))
<- ({h}{e} strengthenFunND notInjImp (F h e) (F2 h e))
<- ({e2} strengthenFunND notInjPair ([h][e] F2 h e e2) ([e] F3 e e2)).

SQtoND_pairl33 : SQtoND (pairl L H D) (pairE00 F00 notInjPair notInjPair F3)


<- hypToCN L H F00
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {e} SQtoND (axiom base h) e -> hypToCN base h e
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {e2} SQtoND (axiom base h2) e2 -> hypToCN base h2 e2 ->
SQtoND (D h h2) (F h e h2 e2)))
<- ({h}{e} strengthenFunND notInjPair (F h e) (F2 h e))

91
<- ({e2} strengthenFunND notInjPair ([h][e] F2 h e e2) ([e] F3 e e2)).

SQtoND_pairl34 : SQtoND (pairl L H D) (pairE01 F00 notInjPair F3)


<- hypToCN L H F00
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {e} SQtoND (axiom base h) e -> hypToCN base h e
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {m2} {n2} copyLF’ n2 m2
-> calcShiftLF’ m2 (shiftLF’ n2) -> hypToCN base h2 (inject m2) -> SQtoND (D h h2) (F h e h2 m2)))
<- ({h}{e} strengthenFunNDLF (F h e) (F2 h e))
<- ({m2} strengthenFunND notInjPair ([h][e] F2 h e m2) ([e] F3 e m2)).

SQtoND_pairl40 : SQtoND (pairl L H D) (pairE10 F00 notInjTop F3)


<- hypToCN L H F00
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {m} {n} copyLF’ n m -> calcShiftLF’ m (shiftLF’ n)
-> hypToCN base h (inject m)
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {e2} SQtoND (axiom base h2) e2 -> hypToCN base h2 e2 ->
SQtoND (D h h2) (F h m h2 e2)))
<- ({h}{m} strengthenFunND notInjTop (F h m) (F2 h m))
<- ({e2} strengthenFunNDLF ([h][m] F2 h m e2) ([m] F3 m e2)).

SQtoND_pairl41 : SQtoND (pairl L H D) (pairE10 F00 notInjBot F3)


<- hypToCN L H F00
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {m} {n} copyLF’ n m -> calcShiftLF’ m (shiftLF’ n)
-> hypToCN base h (inject m)
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {e2} SQtoND (axiom base h2) e2 -> hypToCN base h2 e2 ->
SQtoND (D h h2) (F h m h2 e2)))
<- ({h}{m} strengthenFunND notInjBot (F h m) (F2 h m))
<- ({e2} strengthenFunNDLF ([h][m] F2 h m e2) ([m] F3 m e2)).

SQtoND_pairl42 : SQtoND (pairl L H D) (pairE10 F00 notInjImp F3)


<- hypToCN L H F00
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {m} {n} copyLF’ n m -> calcShiftLF’ m (shiftLF’ n)
-> hypToCN base h (inject m)
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {e2} SQtoND (axiom base h2) e2
-> hypToCN base h2 e2 -> SQtoND (D h h2) (F h m h2 e2)))
<- ({h}{m} strengthenFunND notInjImp (F h m) (F2 h m))
<- ({e2} strengthenFunNDLF ([h][m] F2 h m e2) ([m] F3 m e2)).

SQtoND_pairl43 : SQtoND (pairl L H D) (pairE10 F00 notInjPair F3)


<- hypToCN L H F00
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {m} {n} copyLF’ n m -> calcShiftLF’ m (shiftLF’ n)
-> hypToCN base h (inject m)
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {e2} SQtoND (axiom base h2) e2 -> hypToCN base h2 e2 ->
SQtoND (D h h2) (F h m h2 e2)))
<- ({h}{m} strengthenFunND notInjPair (F h m) (F2 h m))
<- ({e2} strengthenFunNDLF ([h][m] F2 h m e2) ([m] F3 m e2)).

SQtoND_pairl44 : SQtoND (pairl L H D) (pairE11 F00 F3)


<- hypToCN L H F00
<- ({h}{h’} copyH’ h’ base h -> map’ h base (!! h’) -> {m} {n} copyLF’ n m -> calcShiftLF’ m (shiftLF’ n)
-> hypToCN base h (inject m)
-> ({h2}{h2’} copyH’ h2’ base h2 -> map’ h2 base (!! h2’) -> {m2} {n2} copyLF’ n2 m2 -> calcShiftLF’ m2 (shiftLF’ n2)
-> hypToCN base h2 (inject m2) -> SQtoND (D h h2) (F h m h2 m2)))
<- ({h}{m} strengthenFunNDLF (F h m) (F2 h m))
<- ({m2} strengthenFunNDLF ([h][m] F2 h m m2) ([m] F3 m m2)).

%worlds (SQtoNDblockNI | SQtoNDblockInj | lftypeConsBlock) (SQtoND _ _).


%terminates {D} (SQtoND D _).
%total {D} (SQtoND D _).

92
A.12 examples.elf
% Adam Poswolsky
% Example Section

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% LF Application on Meta-Level
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
liftedApp : conc X (!(inj (A arrow B))) -> conc X (!(inj A)) -> conc X (!(inj B)) -> type.
%mode liftedApp +D1 +D2 -F.
liftedAppCase : liftedApp D1 D2 E
<- ({h1}{h1’} copyH’ h1’ base h1 -> map’ h1 base (!! h1’) ->
ca _ D2 stripPastPure ([h2] injr (app (castHyp h1) (castHyp h2)))
(F h1))
<- ca _ D1 stripPastPure F E.
%worlds (mapcopyBlock | lfmapcopyBlock | lftypeConsBlock) (liftedApp _ _ _).
%total {} (liftedApp _ _ _).

93
References
[Aug98] Lennart Augustsson. Cayenne - a language with dependent types. In International Conference on
Functional Programming, pages 239–250, 1998.

[Chu40] Alonzo Church. A formulation of the simple theory of types. Journal of Symbolic Logic, 5:56–68, 1940.

[CX05] Chiyan Chen and Hongwei Xi. Combining programming with theorem proving. In Intenational
Conference on Functional Programming, 2005.

[Dav96] Rowan Davies. A temporal-logic approach to binding-time analysis. In Logic in Computer Science,
pages 184–195, 1996.

[GP99] Murdoch Gabbay and Andrew Pitts. A new approach to abstract syntax involving binders. In
G. Longo, editor, Proceedings of the 14th Annual Symposium on Logic in Computer Science (LICS’99),
pages 214–224, Trento, Italy, July 1999. IEEE Computer Society Press.

[HHP93] Robert Harper, Furio Honsell, and Gordon Plotkin. A framework for defining logics. Journal of the
Association for Computing Machinery, 40(1):143–184, January 1993.

[HMS01] Furio Honsell, Marino Miculan, and Ivan Scagnetto. π-calculus in (Co)inductive-type theory. Theo-
retical Computer Science, 253(2):239–285, 2001.

[Hof99] Martin Hofmann. Semantical analysis for higher-order abstract syntax. In G. Longo, editor, Proceed-
ings of the 14th Annual Symposium on Logic in Computer Science (LICS’99), pages 204–213, Trento,
Italy, July 1999. IEEE Computer Society Press.

[Lel98] Pierre Leleu. Induction et Syntaxe Abstraite d’Ordre Supérieur dans les Théories Typées. PhD thesis,
Ecole Nationale des Ponts et Chaussees, Marne-la-Vallee, France, December 1998.

[MAC03] Alberto Momigliano, Simon Ambler, and Roy Crole. A definitional approach to primitive recursion
over higher order abstract syntax. In Alberto Momigliano and Marino Miculan, editors, Proceedings
of the Merlin Workshop, Uppsala, Sweden, June 2003. ACM Press.

[Mil90] Dale Miller. An extension to ML to handle bound variables in data structures: Preliminary report.
In Proceedings of the Logical Frameworks BRA Workshop, Nice, France, May 1990.

[Mil91] Dale Miller. Unification of simply typed lambda-terms as logic programming. In Koichi Furukawa,
editor, Eighth International Logic Programming Conference, pages 255–269, Paris, France, June 1991.
MIT Press.

[MM04] Conor McBride and James McKinna. The view from the left. Journale of Functional Programming,
14(1), 2004.

[Pau94] Lawrence C. Paulson. Isabelle: A Generic Theorem Prover. Springer-Verlag LNCS 828, 1994.

[Pfe95] Frank Pfenning. Structural cut elimination. In D. Kozen, editor, Proceedings of the Tenth Annual
Symposium on Logic in Computer Science, pages 156–166, San Diego, California, June 1995. IEEE
Computer Society Press.

[Pfe99] Frank Pfenning. Logical frameworks. In Alan Robinson and Andrei Voronkov, editors, Handbook of
Automated Reasoning. Elsevier Science Publishers, 1999. In preparation.

[Pos06] Adam Poswolsky and Carsten Schürmann. Extended Report: A Temporal-Logic Approach to Pro-
gramming with Dependent Types and Higher-Order Encodings. Yale University Tech Report TR-
1355, 2006.
http://www.cs.yale.edu/publications/techreports/tr1355.pdf

[PS98] Frank Pfenning and Carsten Schürmann. Algorithms for equality and unification in the presence of
notational definitions. In T. Altenkirch, W. Naraschewski, and B. Reus, editors, Types for Proofs and
Programs. Springer-Verlag LNCS 1657, 1998. To appear.

[PS99] Frank Pfenning and Carsten Schürmann. System description: Twelf — a meta-logical framework
for deductive systems. In H. Ganzinger, editor, Proceedings of the 16th International Conference on
Automated Deduction (CADE-16), pages 202–206, Trento, Italy, July 1999. Springer-Verlag LNAI
1632.

[Wes06] Edwin Westbrook Free Variable Types Trends in Functional Programming (TFP 2006)
http://www.cs.nott.ac.uk/∼nhn/TFP2006/Papers
/21-Westbrook-FreeVariableTypes.pdf

94
[Sch01] Carsten Schürmann. Recursion for higher-order encodings. In Laurent Fribourg, editor, Proceedings
of the Conference on Computer Science Logic (CSL 2001), pages 585–599, Paris, France, August 2001.
Springer Verlag LNCS 2142.

[Sch05] Carsten Schürmann, Adam Poswolsky, and Jeffrey Sarnat. The ∇-calculus. Functional programming
with higher-order encodings. Typed Lambda Calculus and Applications, TLCA’05 Nara, Japan, 2005.

[SDP01] Carsten Schürmann, Joëlle Despeyroux, and Frank Pfenning. Primitive recursion for higher-order
abstract syntax. Theoretical Computer Science, (266):1–57, 2001.

[SP98] Carsten Schürmann and Frank Pfenning. Automated theorem proving in a simple meta-logic for LF.
In Claude Kirchner and Hélène Kirchner, editors, Proceedings of the 15th International Conference on
Automated Deduction (CADE-15), pages 286–300, Lindau, Germany, July 1998. Springer-Verlag LNAI
1421.

[Sti92] Colin Stirling. Handbook of Logic in Computer Science, volume 2, chapter Modal and Temporal Logics,
pages 478–563. Oxford, 1992.

[Tah04] Walid Taha. A gentle introduction to multi-stage programming. In Don Batory, Charles Con-
sel, Christian Lengauer, and Martin Odersky, editors, Domain-specific Program Generation, LNCS.
Springer-Verlag, 2004. to appear.

[TS00] Walid Taha and Tim Sheard. MetaML: Multi-stage programming with explicit annotations. Theoret-
ical Computer Science, 248(1-2), 2000.

[WaIW05] Edwin Westbrook and Aaron Stump adn Ian Wehrman. A language based approach to functionally
correct imperative programming. In Intenational Conference on Functional Programming, 2005.

[XP99] Hongwei Xi and Frank Pfenning. Dependent types in practical programming. In A. Aiken, editor,
Conference Record of the 26th Symposium on Principles of Programming Languages (POPL’99), pages
214–227. ACM Press, January 1999.

95

You might also like