• No results found

We will now define a declarative syntax for inferences that allows the specification of inferences as well as restrictions on the search process. Figure 9.1 shows the declarative syntax to describe inferences:

< inference > ::= (< name > < eqinf >| <inf>) (where <cond>)? < inf > ::= < prems > ==> < con >+

< eqinf > ::= < prems > < term > == < term > < prems > ::= < prem >| <prem> ; <prems> < prem > ::= ([< forms >] ..)? < form >

< con > ::= < form > | [<form>] < termnode >::= < term >

< cond > ::= < pred >+

< form > ::= < name >: < term >

< form > ::= < form > | <form> , <forms>

Figure 9.1: Basic syntax to define inferences

Having the general form of inferences from Figure 9.1 in mind, the syntax is best explained by examples. We adopt the usual convention to use capital letters to denote meta-variables and lower-case letters to match constants of the domain, existing variables or new Eigenvariables.

• axiom: P ==> P specifies the axiom rule;

• implI: [F] .. P:G ==> C:F => G specifies an inference with a conclusion F => G named C and a single premise G named P and hypotheses F;

• NatInduction: base:P(0) [P(y)] .. step:P(suc(y)) ==> P(x) where new(y) specifies the induction rule for natural numbers naming the cases base and step respectively and requiring the Eigenvariable condition for y.

Please note that each inference corresponds to a formula in Core’s indexed formula tree. This means that quantifiers for free variables need to be reconstructed before the insertion of the formula. Eigenvariables are introduced by a condition new(x;y1, . . . , yn),

indicating that x is an Eigenvariable that must be new with respect to y1, . . . , yn, i.e., must

not occur in y1, . . . , yn. In the case that the inference is generated from an axiom, such a

specification is not necessary, as all conditions are already determined by the axiom. Let us now extend the basic inference language by further annotations, as shown in Figure 9.2. The basic language is the same, but premises and conclusions are replaced by annotated versions < aprem > and < acon >, respectively.

In order to enable the application of an inference, candidates for premises, respectively the conclusion are searched in a sequent. By default, for a premise or conclusion, we search inside all formulas of the sequent for subformulas that unify with the given formula. The annotations < annot > controlling that search are thus attached to each premise and conclusion, respectively, and allow to specify (i) whether or not a partner subformula must be found and how it is identified (< occ >), (ii) if candidates should be searched in subformulas and how the search traverses the formulas (< traversal >), and (iii) when the search for a partner shall be aborted (< abort >). More specifically * and - for a premise or conclusion indicate that a partner must be found for it; in case of * the matching

< aprem > ::= < aform >| [<form>] .. <aform>

< aform > ::= < form > {<annots>}? | [<form>] {<deepannots>}? < deepannots > ::= < annots >? {<restrict>}?

< restrict > ::= only-left | only-right

< annots > ::= < annot > | <annot>, <annots>

< annot > ::= < traversal > | <occ> | <abort> | nopob |<pred> | <pos> < occ > ::= check=< alg > | + | ! | -

< abort > ::= abort=< abort >

< traversal > ::= < lazyall > | <lazyinnerouter> | <first> < lazyall > ::= < direction >,< lazyprogress >

< lazyinnerouter > ::= < innerouter >,< lazyprogress > < first > ::= < innerouter >, < leftright > < direction > ::= Down | Up

< innerouter > ::= innermost | outermost < lazyprogress > ::= LazyLeft| LazyRight < leftright > ::= leftmost| rightmost

< pos > ::= < formulas > (,*)? |- < formulas > (,*)? Figure 9.2: Syntax for Annotated Inferences

formula is kept upon inference application while - requires the matched formula to be replaced. For instance, the alternatively annotated inferences

implI1: [F] .. P:G ==> C:F => G {*} implI2: [F] .. P:G ==> C:F => G {-}

both require to match F => G but only the second also requires to remove it upon appli- cation. As an effect they give result respectively in the following derivations:

Γ, F ⊢ G, F ⇒ G, ∆

Γ⊢ F ⇒ G, ∆ implI1

Γ, F ⊢ G, ∆

Γ⊢ F ⇒ G, ∆ implI2

Finally, the annotation ! indicates that a node must not be instantiated. In order to identify a partner formula, higher-order unification is used in general. To restrict this for instance to HO-matching but also to more specific algorithms, the keyword check allows the restriction to a specific algorithm.

Furthermore, without brackets around the premise/conclusion the partner is searched at top-level among the formulas in the sequent. For a bracketed premise or conclusion [F] the subformulas are searched as well. For instance the annotated inference axiom is only matched against the top-level formulas, while axiom1: [F] ==> F allows for the following derivation

Γ, F ⇒ G ⊢ F, ∆

Γ, F ⇒ G ⊢ G, ∆ axiom1

The next class of annotations specifies how the formula is traversed when looking for subformulas. By default the list of all candidate subformulas is returned. Alterna- tively one can specify a combination of outermost or innermost, in addition with either leftmost or rightmost that the search should stop when the first is found: this can for instance be used to specify inferences to be used for a simplification using a leftmost, innermost strategy. The idea is as follows: A general term traversal can be modelled

by the basic functions visit which performs an action on the current node (which can succeed or fail), and traverse(n), which recursively invokes the traversal function on the nth child node of the current node. A complete term traversal is achieved by visiting all tree nodes in a certain visiting order . By reordering the basic functions we obtain different traversal strategies. There are also more sophisticated traversal strategies such as the level-order traversal, traversing a tree level by level, which require an additional queue to store the elements and which we therefore do not consider as a basic strategy.

Based on ideas of van den Brand [vdBKV03], we allow for different choices according to the traversal cube shown in Figure 9.3: On the first axis, we distinguish procedures that traverse the nodes of a tree bottom up and those that traverse a tree top-down. On the second axis, we classify traversal functions according to those that break the traversal on success and those that traverse the complete tree. On the third axis we distinguish methods that traverse the tree from left to right and those that traverse the tree from right to left. The backtracking behaviour is not represented in the cube.

left-right right-left top-down bottom-up break cont

Figure 9.3: “Traversal Cube”: Principal ways of traversing a tree

In general, one does not always want to compute all partners eagerly, as this might not be efficient. Therefore, we provide the keywords LazyLeft and LazyRight to specify if the formula is traversed from left to right or vice versa. In order to incrementally get all candidates, one can in addition specify in which order they should come: Down prefers outer formulas over inner formulas and Up the other way round. In order to not enumerate all candidates, the keywords innermost and outermost must be used to indicate the preference. In either case, the search algorithm returns a candidate subformula along with a substitution and a continuation to be used for the next candidate. That continuation is used for backtracking during the candidate search process as well as outside: if the candidate search for other required premises fails because of the used substitution, the search process uses the continuation to get the next possible candidate. If the overall inference application succeeds, the collected continuations can be saved by the strategy process and be used in case the strategy wants to backtrack.