8.6 Quote

## 8.6 `Quote`

The tactic `Quote` allows to use Barendregt's so-called 2-level approach without writing any ML code. Suppose you have a language `L` of 'abstract terms' and a type `A` of 'concrete terms' and a function `f : L -> A`. If `L` is a simple inductive datatype and `f` a simple fixpoint, `Quote f` will replace the head of current goal by a convertible term of the form `(f t)`. `L` must have a constructor of type: `A -> L`.
Here is an example:
`Coq` `<``Require Quote.`
`Coq` `<``Parameters A,B,C:Prop.`
`A is assumed`
`B is assumed`
`C is assumed`
`Coq` `<``Inductive Type formula :=`
`Coq` `<``| f_and : formula -``>``formula -``>``formula (* binary constructor *)`
`Coq` `<``| f_or : formula -``>``formula -``>``formula`
`Coq` `<``| f_not : formula -``>``formula (* unary constructor *)`
`Coq` `<``| f_true : formula (* 0-ary constructor *)`
`Coq` `<``| f_const : Prop -``>``formula (* contructor for constants *).`
`formula is defined`
`formula_rect is defined`
`formula_ind is defined`
`formula_rec is defined`
`Coq` `<```
`Coq` `<``Fixpoint interp_f [f:formula] : Prop :=`
`Coq` `<``Cases f of`
`Coq` `<``| (f_and f1 f2) =``>``(interp_f f1)/\(interp_f f2)`
`Coq` `<``| (f_or f1 f2) =``>``(interp_f f1)\/(interp_f f2)`
`Coq` `<``| (f_not f1) =``>``~(interp_f f1)`
`Coq` `<``| f_true =``>``True`
`Coq` `<``| (f_const c) =``>``c`
`Coq` `<``end.`
`interp_f is recursively defined`
`Coq` `<``Goal A/\(A\/True)/\~B/\(A` `<``-``>``A).`
`1 subgoal`
``
`============================`
`A/\(A\/True)/\~B/\(A``<``-``>``A)`
`Coq` `<``Quote interp_f.`
`1 subgoal`
``
`============================`
`(interp_f`
`(f_and (f_const A)`
`(f_and (f_or (f_const A) f_true)`
`(f_and (f_not (f_const B)) (f_const A``<``-``>``A)))))`
The algorithm to perform this inversion is: try to match the term with right-hand sides expression of `f`. If there is a match, apply the corresponding left-hand side and call yourself recursively on sub-terms. If there is no match, we are at a leaf: return the corresponding constructor (here `f_const`) applied to the term.
Error messages:

1. `Quote: not a simple fixpoint`
   Happens when `Quote` is not able to perform inversion properly.

### 8.6.1 Introducing variables map

The normal use of `Quote` is to make proofs by reflection: one defines a function `simplify : formula -> formula` and proves a theorem `simplify_ok: (f:formula)(interp_f (simplify f)) -> (interp_f f)`. Then, one can simplify formulas by doing:

>        Quote interp_f.
>        Apply simplify_ok.
>        Compute.

But there is a problem with leafs: in the example above one cannot write a function that implements, for example, the logical simplifications A Ù A ® A or A Ù ¬ A ® `False`. This is because the Prop is impredicative.
It is better to use that type of formulas:
`Coq` `<``Inductive Set formula :=`
`Coq` `<``| f_and : formula -``>``formula -``>``formula`
`Coq` `<``| f_or : formula -``>``formula -``>``formula`
`Coq` `<``| f_not : formula -``>``formula`
`Coq` `<``| f_true : formula`
`Coq` `<``| f_atom : index -``>``formula.`
`formula is defined`
`formula_rect is defined`
`formula_ind is defined`
`formula_rec is defined`
`index` is defined in module `Quote`. Equality on that type is decidable so we are able to simplify A Ù A into A at the abstract level.
When there are variables, there are bindings, and `Quote` provides also a type `(varmap A)` of bindings from `index` to any set `A`, and a function `varmap_find` to search in such maps. The interpretation function has now another argument, a variables map:
`Coq` `<``Fixpoint interp_f [vm:(varmap Prop); f:formula] : Prop :=`
`Coq` `<``Cases f of`
`Coq` `<``| (f_and f1 f2) =``>``(interp_f vm f1)/\(interp_f vm f2)`
`Coq` `<``| (f_or f1 f2) =``>``(interp_f vm f1)\/(interp_f vm f2)`
`Coq` `<``| (f_not f1) =``>``~(interp_f vm f1)`
`Coq` `<``| f_true =``>``True`
`Coq` `<``| (f_atom i) =``>``(varmap_find True i vm)`
`Coq` `<``end.`
`interp_f is recursively defined`
`Quote` handles this second case properly:
`Coq` `<``Goal A/\(B\/A)/\(A\/~B).`
`1 subgoal`
``
`============================`
`A/\(B\/A)/\(A\/~B)`
`Coq` `<``Quote interp_f.`
`1 subgoal`
``
`============================`
`(interp_f`
`(Node_vm B (Node_vm A (Empty_vm Prop) (Empty_vm Prop))`
`(Empty_vm Prop))`
`(f_and (f_atom (Left_idx End_idx))`
`(f_and (f_or (f_atom End_idx) (f_atom (Left_idx End_idx)))`
`(f_or (f_atom (Left_idx End_idx)) (f_not (f_atom End_idx))))))`
It builds `vm` and `t` such that `(f vm t)` is convertible with the conclusion of current goal.

### 8.6.2 Combining variables and constants

One can have both variables and constants in abstracts terms; that is the case, for example, for the `Ring` tactic (chapter 18). Then one must provide to Quote a list of constructors of constants. For example, if the list is `[O S]` then closed natural numbers will be considered as constants and other terms as variables.
Example:
`Coq` `<``Inductive Type formula :=`
`Coq` `<``| f_and : formula -``>``formula -``>``formula`
`Coq` `<``| f_or : formula -``>``formula -``>``formula`
`Coq` `<``| f_not : formula -``>``formula`
`Coq` `<``| f_true : formula`
`Coq` `<``| f_const : Prop -``>``formula (* constructor for constants *)`
`Coq` `<``| f_atom : index -``>``formula. (* constructor for variables *)`
`Coq` `<```
`Coq` `<``Fixpoint interp_f [vm:(varmap Prop); f:formula] : Prop :=`
`Coq` `<``Cases f of`
`Coq` `<``| (f_and f1 f2) =``>``(interp_f vm f1)/\(interp_f vm f2)`
`Coq` `<``| (f_or f1 f2) =``>``(interp_f vm f1)\/(interp_f vm f2)`
`Coq` `<``| (f_not f1) =``>``~(interp_f vm f1)`
`Coq` `<``| f_true =``>``True`
`Coq` `<``| (f_const c) =``>``c`
`Coq` `<``| (f_atom i) =``>``(varmap_find True i vm)`
`Coq` `<``end.`
`Coq` `<```
`Coq` `<``Goal A/\(A\/True)/\~B/\(C``<``-``>``C).`
`Coq` `<``Quote interp_f [A B].`
`1 subgoal`
``
`============================`
`(interp_f (Node_vm C``<``-``>``C (Empty_vm Prop) (Empty_vm Prop))`
`(f_and (f_const A)`
`(f_and (f_or (f_const A) f_true)`
`(f_and (f_not (f_const B)) (f_atom End_idx)))))`
`Coq` `<``Undo. Quote interp_f [B C iff].`
`1 subgoal`
``
`============================`
`A/\(A\/True)/\~B/\(C``<``-``>``C)`
`1 subgoal`
``
`============================`
`(interp_f (Node_vm A (Empty_vm Prop) (Empty_vm Prop))`
`(f_and (f_atom End_idx)`
`(f_and (f_or (f_atom End_idx) f_true)`
`(f_and (f_not (f_const B)) (f_const C``<``-``>``C)))))`
Warning: Since function inversion is undecidable in general case, don't expect miracles from it!
See also: comments of source file `tactics/contrib/polynom/quote.ml`
See also: the tactic `Ring` (chapter 18)