4. Constants

Pconst

Every constant (or more precisely, object constant) has a type and denotes a computable (hence continuous) functional of that type. We have the following three kinds of constants:

The latter are built into the system: recursion operators for arbitrary algebras, equality and existence operators for finitary algebras, and existence elimination. They are typed in parametrized form, with the actual type (or formula) given by a type (or type and formula) substitution that is also part of the constant. For instance, equality is typed by α α boole and a type substitution α↦→ρ. This is done for clarity (and brevity, e.g. for large ρ in the example above), since one should think of the type of a constant in this way.

For constructors and for constants with fixed rules, by efficiency reasons we want to keep the object denoted by the constant (as needed for normalization by evaluation) as part of it. It depends on the type of the constant, hence must be updated in a given proof whenever the type changes by a type substitution.

4.1. Rewrite and computation rules for program constants.

SS:RewCompRules

For every program constant cρ we assume that some rewrite rules of the form c⃗K↦→N are given, where FV(N) FV(⃗K) and c⃗K, N have the same type (not necessarily a ground type). Moreover, for any two rules c ⃗
K↦→N and cK⃗↦→Nwe require that ⃗K and ⃗Kare of the same length, called the arity of c. The rules are divided into computation rules and proper rewrite rules. They must satisfy the requirements listed in [4]. The idea is that a computation rule can be understood as a description of a computation in a suitable semantical model, provided the syntactic constructors correspond to semantic ones in the model, whereas the other rules describe syntactic transformations.

There a more general approach was used: one may enter into components of products. Then instead of one arity one needs several “type informations” ⃗ρ σ with ⃗ρ a list of types, 0’s and 1’s indicating the left or right part of a product type. For example, if c is of type τ (τ τ τ) × (τ τ), then the rules cy0xx↦→a and cy1↦→b are admitted, and c comes with the type informations (τ,0,τ,τ τ) τ and (τ,1) (τ τ). – However, for simplicity we only deal with a single arity here.

Given a set of rewrite rules, we want to treat some rules - which we call computation rules - in a different, more efficient way. The idea is that a computation rule can be understood as a description of a computation in a suitable semantical model, provided the syntactic constructors correspond to semantic ones in the model, whereas the other rules describe syntactic transformations.

In order to define what we mean by computation rules, we need the notion of a constructor pattern. These are special terms defined inductively as follows.

From the given set of rewrite rules we choose a subset Comp with the following properties.

We write c⃗M↦→compQ to indicate that the rule is in Comp. All other rules will be called (proper) rewrite rules, written c ⃗
M↦→rewK.

In our reduction strategy computation rules will always be applied first, and since they are non-overlapping, this part of the reduction is unique. However, since we allowed almost arbitrary rewrite rules, it may happen that in case no computation rule applies a term may be rewritten by different rules ∕∈Comp. In order to obtain a deterministic procedure we then select the first applicable rewrite rule (This is a slight simplification of [4], where special functions selc were used for this purpose).

4.2. Recursion over simultaneous free algebras.

SS:RecSFA

We now explain what we mean by recursion over simultaneous free algebras. The inductive structure of the types ⃗μ = μ⃗α⃗κ corresponds to two sorts of constants. With the constructors constri⃗μ: κi[⃗μ] we can construct elements of a type μj, and with the recursion operators μj⃗μ,⃗τ we can construct mappings from μj to τj by recursion on the structure of ⃗μ. So in (Rec arrow-types), arrow-types is a list μ1 τ1,k τk. Here μ1,k are the algebras defined simultaneously and τ1,k are the result types.

For convenience in our later treatment of proofs (when we want to normalize a proof by (1) translating it into a term, (2) normalizing this term and (3) translating the normal term back into a proof), we also allow all-formulas x1μ1A1,,xkμkAk instead of arrow-types: they are treated as μ1 τ(A1), ..., μk τ(Ak) with τ(Aj) the type of Aj.

Recall the definition of types and constructor types in Section 2, and the examples given there. In order to define the type of the recursion operators w.r.t. ⃗μ = μ⃗α⃗κ and result types ⃗τ, we first define for

κi = ⃗ρ → (⃗σ1 → αj1) → ⋅⋅⋅ → (⃗σn → αjn) → αj ∈ KT( ⃗α)

the step type

δi⃗μ,⃗τ := ⃗ρ (⃗σ 1 μj1) ⋅⋅⋅(⃗σn μjn)
(⃗σ1 τj1) ⋅⋅⋅(⃗σn τjn) τj.
Here ⃗ρ,(⃗σ1 μj1),,(⃗σn μjn) correspond to the components of the object of type μj under consideration, and (⃗σ1 τj1),,(⃗σn τjn) to the previously defined values. The recursion operator μj⃗μ,⃗τ has type
ℛ ⃗μ,⃗τ: δ⃗μ,⃗τ → ⋅⋅⋅ → δ⃗μ,⃗τ →  μj → τj.
  μj   1           k

We will often write j⃗μ,⃗τ for μj⃗μ,⃗τ, and omit the upper indices ⃗μ,⃗τ when they are clear from the context. In case of a non-simultaneous free algebra, i.e. of type μα (κ), for μμ,τ we normally write μτ.

A simple example for simultaneous free algebras is

(tree,tlist) := μ(α,β) (α,β → α, β,α → β → β).

The constructors are

Leaftree := constr 1(tree,tlist),
Branchtlisttree := constr 2(tree,tlist),
Emptytlist := constr 3(tree,tlist),
Tconstreetlisttlist := constr 4(tree,tlist).
An example for a recursion constant is
(const Rec δ1 δ2 δ3 δ4 tree α1
(α1↦→τ12↦→τ2))
with
δ1 := α1,
δ2 := tlist α2 α1,
δ3 := α2,
δ4 := tree tlist α1 α2 α2.
Here the fact that we deal with a simultaneous recursion (over tree and tlist), and that we define a constant of type tree , can all be inferred from what is given: the type tree is right there, and for tlist we can look up the simultaneously defined algebras.

For the external representation (i.e. display) we use the shorter notation

(Rec tree →  τ  tlist → τ ).
             1        2

As already mentioned, it is also possible that the object constant Rec comes with formulas instead of types, as the assumption constant Ind below. This is due to our desire not to duplicate code when normalizing proofs, but rather translate the proof into a term first, normalize the term and then translate back into a proof. For the last step we must have the original formulas of the induction operator available.

To see a concrete example, let us recursively define addition +: tree tree tree and : tlist tree tlist. The recursion equations to be satisfied are

+ Leaf = λaa,
+ (Branchbs) = λa.Branch(bs a),
Empty = λaEmpty,
(Tconsbbs) = λa.Tcons(+ba)(bs a).
We define + and by means of the recursion operators tree and tlist with result types
τ1 := tree tree,
τ2 := tree tlist.
The step terms are
M1 := λaa,
M2 := λbsλgτ2 λa.Branch(g a),
M3 := λaEmpty,
M4 := λbλbsλfτ1 λgτ2 λa.Tcons(f a)(g a).
Then
+ := treeM⃗: tree tree tree,
:= tlist ⃗
M: tlist tree tlist.

To explain the conversion relation, it will be useful to employ the following notation. Let ⃗μ = μ⃗α⃗κ,

κi = ρ1 → ⋅⋅⋅ → ρm →  (⃗σ1 → αj1) → ⋅⋅⋅ → (⃗σn → αjn) → αj ∈ KT( ⃗α),

and consider constri⃗μN⃗. Then we write N⃗P = N1P ,,NmP for the parameter arguments N1ρ1,,Nmρm and N⃗R = N1R,,NnR for the recursive arguments Nm+1⃗σ1μj1,,Nm+n⃗σnμjn, and nR for the number n of recursive arguments.

We define a conversion relation ↦→ρ between terms of type ρ by

(λxM)N ↦→M[x:=N] (1)
λx.Mx ↦→M if x∕∈FV(M), M not an abstraction (2)
(j⃗μ,⃗τM⃗)μjτj (constri⃗μN⃗) ↦→M i⃗N((j 1⃗μ,⃗τM⃗) N 1R)(( jn⃗μ,⃗τM⃗) N nR) (3)
Here we have written j⃗μ,⃗τ for μj⃗μ,⃗τ, and means composition.

4.3. Internal representation of constants. Every object constant has the internal representation

(const  object-or-arity name uninst-type-or-formula subst
t-deg token-type arrow-types-or-repro-formulas),
where subst may have type, object and assumption variables in its domain. The type of the constant is the result of carrying out this substitution in uninst-type-or-formula (if this is a type; otherwise first substitute and then convert the formula into a type); free type variables may again occur in this type. Note that a formula will occur if name is Ex-Intro or Ex-Elim, and may occur if it is Rec. Examples for object constants are
(const Compose (αβ)(βγ)αγ (α↦→ρ,β↦→σ,γ↦→τ) ...)
(const Eq α α boole (α↦→finalg) ...)
(const E α boole (α↦→finalg))
(const Ex-Elim xαP(x) (xα.P(x) Q) Q
(α↦→τ,P(α)↦→{zτ A},Q↦→{ ∣ B }) ...)
object-or-arity is an object if this object cannot be changed, e.g. by allowing user defined rules for the constant; otherwise, the associated object needs to be updated whenever a new rule is added, and we have the arity of those rules instead. The rules are of crucial importance for the correctness of a proof, and should not be invisibly buried in the denoted object taken as part of the constant (hence of any term involving it). Therefore we keep the rules of a program constant and also its denoted objects (depending on type substitutions) at a central place, a global variable PROGRAM-CONSTANTS which assigns to every name of such a constant the constant itself (with uninstantiated type), the rules presently chosen for it and also its denoted objects (as association list with type substitutions as keys). When a new rule has been added, the new objects for the program constant are computed, and the new list to be associated with the program constant is written in PROGRAM-CONSTANTS instead. All information on a program constant exept its denoted object and its computation and rewrite rules (i.e. its type, degree of totality, arity and token type) is stable and hence can be kept as part of it. The token type can be either const (i.e. constant written as application) or one of: postfix-op, prefix-op, binding-op, add-op, mul-op, rel-op, and-op, or-op, imp-op and pair-op.

Constructor, accessors and tests for all kinds of constants:

(make-const obj-or-arity name kind uninst-type tsubst
t-deg token-type . arrow-types-or-repro-formulas)
(const-to-object-or-arity const)
(const-to-name const)
(const-to-kind const)
(const-to-uninst-type const)
(const-to-tsubst const)
(const-to-t-deg const)
(const-to-token-type const)
(const-to-arrow-types-or-repro-formulas const)
(const? x)
(const=? x y)
The type substitution tsubst must be restricted to the type variables in uninst-type. arrow-types-or-repro-formulas are only present for the Rec constants. They are needed for the reproduction case.

From these we can define

(const-to-type const)
(const-to-tvars const)

A constructor is a special constant with no rules. We maintain an association list CONSTRUCTORS assigning to every name of a constructor an association list associating with every type substitution (restricted to the type parameters) the corresponding instance of the constructor. We provide

(constr-name? string)
(constr-name-to-constr name <tsubst>)
(constr-name-and-tsubst-to-constr name tsubst),
where in (constr-name-to-constr name <tsubst>), name is a string or else of the form (Ex-Intro formula). If the optional tsubst is not present, the empty substitution is used.

For given algebras one can display the associated constructors with their types by calling

(display-constructors alg-name1 ...).

We also need procedures recovering information from the string denoting a program constant (via PROGRAM-CONSTANTS):

(pconst-name-to-pconst name)
(pconst-name-to-comprules name)
(pconst-name-to-rewrules name)
(pconst-name-to-inst-objs name)
(pconst-name-and-tsubst-to-object name tsubst)
(pconst-name-to-object name).

One can display the program constants together with their current computation and rewrite rules by calling

(display-program-constants name1 ...).

To add and remove program constants we use

(add-program-constant name type <rest>)
(remove-program-constant symbol);
rest consists of an initial segment of the following list: t-deg (default 0), token-type (default const) and arity (default maximal number of argument types).

To add and remove computation and rewrite rules we have

(add-computation-rule lhs rhs)
(add-rewrite-rule lhs rhs)
(remove-computation-rules-for lhs)
(remove-rewrite-rules-for lhs).

To generate our constants with fixed rules we use

(finalg-to-=-const finalg) equality
(finalg-to-e-const finalg) existence
(arrow-types-to-rec-const . arrow-types) recursion
(ex-formula-and-concl-to-ex-elim-const
ex-formula concl)

Similarly to arrow-types-to-rec-const we also define the procedure all-formulas-to-rec-const. It will be used in to achieve normalization of proofs via translating them in terms.

[Noch einfügen: arrow-types-to-cases-const und zur Behandlung von Beweisen all-formulas-to-cases-const]