aboutsummaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authorMaxime Dénès2019-04-25 12:02:43 +0200
committerMaxime Dénès2019-04-25 12:09:44 +0200
commit66b6e83f4f4c32ad86333e13d65329be02c46048 (patch)
treea7c2ae2edfe69f8a207d990b6f34f7a497615a27 /doc
parent5131640774d0256a390790b5becc864935585ce8 (diff)
Prepare merge into Coq
Diffstat (limited to 'doc')
-rw-r--r--doc/ltac2.md1036
1 files changed, 0 insertions, 1036 deletions
diff --git a/doc/ltac2.md b/doc/ltac2.md
deleted file mode 100644
index b217cb08e6..0000000000
--- a/doc/ltac2.md
+++ /dev/null
@@ -1,1036 +0,0 @@
-# Summary
-
-The Ltac tactic language is probably one of the ingredients of the success of
-Coq, yet it is at the same time its Achilles' heel. Indeed, Ltac:
-
-- has nothing like intended semantics
-- is very non-uniform due to organic growth
-- lacks expressivity and requires programming-by-hacking
-- is slow
-- is error-prone and fragile
-- has an intricate implementation
-
-This has a lot of terrible consequences, most notably the fact that it is never
-clear whether some observed behaviour is a bug or a proper one.
-
-Following the need of users that start developing huge projects relying
-critically on Ltac, we believe that we should offer a proper modern language
-that features at least the following:
-
-- at least informal, predictable semantics
-- a typing system
-- standard programming facilities (i.e. datatypes)
-
-This document describes the implementation of such a language. The
-implementation of Ltac as of Coq 8.7 will be referred to as Ltac1.
-
-# Contents
-
-<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->
-**Table of Contents**
-
-- [Summary](#summary)
-- [Contents](#contents)
-- [General design](#general-design)
-- [ML component](#ml-component)
- - [Overview](#overview)
- - [Type Syntax](#type-syntax)
- - [Type declarations](#type-declarations)
- - [Term Syntax](#term-syntax)
- - [Ltac Definitions](#ltac-definitions)
- - [Reduction](#reduction)
- - [Typing](#typing)
- - [Effects](#effects)
- - [Standard IO](#standard-io)
- - [Fatal errors](#fatal-errors)
- - [Backtrack](#backtrack)
- - [Goals](#goals)
-- [Meta-programming](#meta-programming)
- - [Overview](#overview-1)
- - [Generic Syntax for Quotations](#generic-syntax-for-quotations)
- - [Built-in quotations](#built-in-quotations)
- - [Strict vs. non-strict mode](#strict-vs-non-strict-mode)
- - [Term Antiquotations](#term-antiquotations)
- - [Syntax](#syntax)
- - [Semantics](#semantics)
- - [Static semantics](#static-semantics)
- - [Dynamic semantics](#dynamic-semantics)
- - [Trivial Term Antiquotations](#trivial-term-antiquotations)
- - [Match over terms](#match-over-terms)
- - [Match over goals](#match-over-goals)
-- [Notations](#notations)
- - [Scopes](#scopes)
- - [Notations](#notations-1)
- - [Abbreviations](#abbreviations)
-- [Evaluation](#evaluation)
-- [Debug](#debug)
-- [Compatibility layer with Ltac1](#compatibility-layer-with-ltac1)
- - [Ltac1 from Ltac2](#ltac1-from-ltac2)
- - [Ltac2 from Ltac1](#ltac2-from-ltac1)
-- [Transition from Ltac1](#transition-from-ltac1)
- - [Syntax changes](#syntax-changes)
- - [Tactic delay](#tactic-delay)
- - [Variable binding](#variable-binding)
- - [In Ltac expressions](#in-ltac-expressions)
- - [In quotations](#in-quotations)
- - [Exception catching](#exception-catching)
-- [TODO](#todo)
-
-<!-- markdown-toc end -->
-
-
-# General design
-
-There are various alternatives to Ltac1, such that Mtac or Rtac for instance.
-While those alternatives can be quite distinct from Ltac1, we designed
-Ltac2 to be closest as reasonably possible to Ltac1, while fixing the
-aforementioned defects.
-
-In particular, Ltac2 is:
-- a member of the ML family of languages, i.e.
- * a call-by-value functional language
- * with effects
- * together with Hindley-Milner type system
-- a language featuring meta-programming facilities for the manipulation of
- Coq-side terms
-- a language featuring notation facilities to help writing palatable scripts
-
-We describe more in details each point in the remainder of this document.
-
-# ML component
-
-## Overview
-
-Ltac2 is a member of the ML family of languages, in the sense that it is an
-effectful call-by-value functional language, with static typing à la
-Hindley-Milner. It is commonly accepted that ML constitutes a sweet spot in PL
-design, as it is relatively expressive while not being either too lax
-(contrarily to dynamic typing) nor too strict (contrarily to say, dependent
-types).
-
-The main goal of Ltac2 is to serve as a meta-language for Coq. As such, it
-naturally fits in the ML lineage, just as the historical ML was designed as
-the tactic language for the LCF prover. It can also be seen as a general-purpose
-language, by simply forgetting about the Coq-specific features.
-
-Sticking to a standard ML type system can be considered somewhat weak for a
-meta-language designed to manipulate Coq terms. In particular, there is no
-way to statically guarantee that a Coq term resulting from an Ltac2
-computation will be well-typed. This is actually a design choice, motivated
-by retro-compatibility with Ltac1. Instead, well-typedness is deferred to
-dynamic checks, allowing many primitive functions to fail whenever they are
-provided with an ill-typed term.
-
-The language is naturally effectful as it manipulates the global state of the
-proof engine. This allows to think of proof-modifying primitives as effects
-in a straightforward way. Semantically, proof manipulation lives in a monad,
-which allows to ensure that Ltac2 satisfies the same equations as a generic ML
-with unspecified effects would do, e.g. function reduction is substitution
-by a value.
-
-## Type Syntax
-
-At the level of terms, we simply elaborate on Ltac1 syntax, which is quite
-close to e.g. the one of OCaml. Types follow the simply-typed syntax of OCaml.
-
-```
-TYPE :=
-| "(" TYPE₀ "," ... "," TYPEₙ ")" TYPECONST
-| "(" TYPE₀ "*" ... "*" TYPEₙ ")"
-| TYPE₁ "->" TYPE₂
-| TYPEVAR
-
-TYPECONST := ( MODPATH "." )* LIDENT
-
-TYPEVAR := "'" LIDENT
-
-TYPEPARAMS := "(" TYPEVAR₀ "," ... "," TYPEVARₙ ")"
-```
-
-The set of base types can be extended thanks to the usual ML type
-declarations such as algebraic datatypes and records.
-
-Built-in types include:
-- `int`, machine integers (size not specified, in practice inherited from OCaml)
-- `string`, mutable strings
-- `'a array`, mutable arrays
-- `exn`, exceptions
-- `constr`, kernel-side terms
-- `pattern`, term patterns
-- `ident`, well-formed identifiers
-
-## Type declarations
-
-One can define new types by the following commands.
-
-```
-VERNAC ::=
-| "Ltac2" "Type" TYPEPARAMS LIDENT
-| "Ltac2" "Type" RECFLAG TYPEPARAMS LIDENT ":=" TYPEDEF
-
-RECFLAG := ( "rec" )
-```
-
-The first command defines an abstract type. It has no use for the end user and
-is dedicated to types representing data coming from the OCaml world.
-
-The second command defines a type with a manifest. There are four possible
-kinds of such definitions: alias, variant, record and open variant types.
-
-```
-TYPEDEF :=
-| TYPE
-| "[" CONSTRUCTORDEF₀ "|" ... "|" CONSTRUCTORDEFₙ "]"
-| "{" FIELDDEF₀ ";" ... ";" FIELDDEFₙ "}"
-| "[" ".." "]"
-
-CONSTRUCTORDEF :=
-| IDENT ( "(" TYPE₀ "," ... "," TYPE₀ ")" )
-
-FIELDDEF :=
-| MUTFLAG IDENT ":" TYPE
-
-MUTFLAG := ( "mutable" )
-```
-
-Aliases are just a name for a given type expression and are transparently
-unfoldable to it. They cannot be recursive.
-
-Variants are sum types defined by constructors and eliminated by
-pattern-matching. They can be recursive, but the `RECFLAG` must be explicitly
-set. Pattern-maching must be exhaustive.
-
-Records are product types with named fields and eliminated by projection.
-Likewise they can be recursive if the `RECFLAG` is set.
-
-Open variants are a special kind of variant types whose constructors are not
-statically defined, but can instead be extended dynamically. A typical example
-is the standard `exn` type. Pattern-matching must always include a catch-all
-clause. They can be extended by the following command.
-
-```
-VERNAC ::=
-| "Ltac2" "Type" TYPEPARAMS QUALID ":=" "[" CONSTRUCTORDEF "]"
-```
-
-## Term Syntax
-
-The syntax of the functional fragment is very close to the one of Ltac1, except
-that it adds a true pattern-matching feature, as well as a few standard
-constructions from ML.
-
-```
-VAR := LIDENT
-
-QUALID := ( MODPATH "." )* LIDENT
-
-CONSTRUCTOR := UIDENT
-
-TERM :=
-| QUALID
-| CONSTRUCTOR TERM₀ ... TERMₙ
-| TERM TERM₀ ... TERMₙ
-| "fun" VAR "=>" TERM
-| "let" VAR ":=" TERM "in" TERM
-| "let" "rec" VAR ":=" TERM "in" TERM
-| "match" TERM "with" BRANCH* "end"
-| INT
-| STRING
-| "[|" TERM₀ ";" ... ";" TERMₙ "|]"
-| "(" TERM₀ "," ... "," TERMₙ ")"
-| "{" FIELD+ "}"
-| TERM "." "(" QUALID ")"
-| TERM₁ "." "(" QUALID ")" ":=" TERM₂
-| "["; TERM₀ ";" ... ";" TERMₙ "]"
-| TERM₁ "::" TERM₂
-| ...
-
-BRANCH :=
-| PATTERN "=>" TERM
-
-PATTERN :=
-| VAR
-| "_"
-| "(" PATTERN₀ "," ... "," PATTERNₙ ")"
-| CONSTRUCTOR PATTERN₀ ... PATTERNₙ
-| "[" "]"
-| PATTERN₁ "::" PATTERN₂
-
-FIELD :=
-| QUALID ":=" TERM
-
-```
-
-In practice, there is some additional syntactic sugar that allows e.g. to
-bind a variable and match on it at the same time, in the usual ML style.
-
-There is a dedicated syntax for list and array litterals.
-
-Limitations: for now, deep pattern matching is not implemented yet.
-
-## Ltac Definitions
-
-One can define a new global Ltac2 value using the following syntax.
-```
-VERNAC ::=
-| "Ltac2" MUTFLAG RECFLAG LIDENT ":=" TERM
-```
-
-For semantic reasons, the body of the Ltac2 definition must be a syntactical
-value, i.e. a function, a constant or a pure constructor recursively applied to
-values.
-
-If the `RECFLAG` is set, the tactic is expanded into a recursive binding.
-
-If the `MUTFLAG` is set, the definition can be redefined at a later stage. This
-can be performed through the following command.
-
-```
-VERNAC ::=
-| "Ltac2" "Set" QUALID ":=" TERM
-```
-
-Mutable definitions act like dynamic binding, i.e. at runtime, the last defined
-value for this entry is chosen. This is useful for global flags and the like.
-
-## Reduction
-
-We use the usual ML call-by-value reduction, with an otherwise unspecified
-evaluation order. This is a design choice making it compatible with OCaml,
-if ever we implement native compilation. The expected equations are as follows.
-```
-(fun x => t) V ≡ t{x := V} (βv)
-
-let x := V in t ≡ t{x := V} (let)
-
-match C V₀ ... Vₙ with ... | C x₀ ... xₙ => t | ... end ≡ t {xᵢ := Vᵢ} (ι)
-
-(t any term, V values, C constructor)
-```
-
-Note that call-by-value reduction is already a departure from Ltac1 which uses
-heuristics to decide when evaluating an expression. For instance, the following
-expressions do not evaluate the same way in Ltac1.
-
-```
-foo (idtac; let x := 0 in bar)
-
-foo (let x := 0 in bar)
-```
-
-Instead of relying on the `idtac` hack, we would now require an explicit thunk
-not to compute the argument, and `foo` would have e.g. type
-`(unit -> unit) -> unit`.
-
-```
-foo (fun () => let x := 0 in bar)
-```
-
-## Typing
-
-Typing is strict and follows Hindley-Milner system. We will not implement the
-current hackish subtyping semantics, and one will have to resort to conversion
-functions. See notations though to make things more palatable.
-
-In this setting, all usual argument-free tactics have type `unit -> unit`, but
-one can return as well a value of type `t` thanks to terms of type `unit -> t`,
-or take additional arguments.
-
-## Effects
-
-Regarding effects, nothing involved here, except that instead of using the
-standard IO monad as the ambient effectful world, Ltac2 is going to use the
-tactic monad.
-
-Note that the order of evaluation of application is *not* specified and is
-implementation-dependent, as in OCaml.
-
-We recall that the `Proofview.tactic` monad is essentially a IO monad together
-with backtracking state representing the proof state.
-
-Intuitively a thunk of type `unit -> 'a` can do the following:
-- It can perform non-backtracking IO like printing and setting mutable variables
-- It can fail in a non-recoverable way
-- It can use first-class backtrack. The proper way to figure that is that we
- morally have the following isomorphism:
- `(unit -> 'a) ~ (unit -> exn + ('a * (exn -> 'a)))` i.e. thunks can produce a
- lazy list of results where each tail is waiting for a continuation exception.
-- It can access a backtracking proof state, made out amongst other things of
- the current evar assignation and the list of goals under focus.
-
-We describe more thoroughly the various effects existing in Ltac2 hereafter.
-
-### Standard IO
-
-The Ltac2 language features non-backtracking IO, notably mutable data and
-printing operations.
-
-Mutable fields of records can be modified using the set syntax. Likewise,
-built-in types like `string` and `array` feature imperative assignment. See
-modules `String` and `Array` respectively.
-
-A few printing primitives are provided in the `Message` module, allowing to
-display information to the user.
-
-### Fatal errors
-
-The Ltac2 language provides non-backtracking exceptions through the
-following primitive in module `Control`.
-
-```
-val throw : exn -> 'a
-```
-
-Contrarily to backtracking exceptions from the next section, this kind of error
-is never caught by backtracking primitives, that is, throwing an exception
-destroys the stack. This is materialized by the following equation, where `E`
-is an evaluation context.
-
-```
-E[throw e] ≡ throw e
-
-(e value)
-```
-
-There is currently no way to catch such an exception and it is a design choice.
-There might be at some future point a way to catch it in a brutal way,
-destroying all backtrack and return values.
-
-### Backtrack
-
-In Ltac2, we have the following backtracking primitives, defined in the
-`Control` module.
-
-```
-Ltac2 Type 'a result := [ Val ('a) | Err (exn) ].
-
-val zero : exn -> 'a
-val plus : (unit -> 'a) -> (exn -> 'a) -> 'a
-val case : (unit -> 'a) -> ('a * (exn -> 'a)) result
-```
-
-If one sees thunks as lazy lists, then `zero` is the empty list and `plus` is
-list concatenation, while `case` is pattern-matching.
-
-The backtracking is first-class, i.e. one can write
-`plus (fun () => "x") (fun _ => "y") : string` producing a backtracking string.
-
-These operations are expected to satisfy a few equations, most notably that they
-form a monoid compatible with sequentialization.
-
-```
-plus t zero ≡ t ()
-plus (fun () => zero e) f ≡ f e
-plus (plus t f) g ≡ plus t (fun e => plus (f e) g)
-
-case (fun () => zero e) ≡ Err e
-case (fun () => plus (fun () => t) f) ≡ Val t f
-
-let x := zero e in u ≡ zero e
-let x := plus t f in u ≡ plus (fun () => let x := t in u) (fun e => let x := f e in u)
-
-(t, u, f, g, e values)
-```
-
-### Goals
-
-A goal is given by the data of its conclusion and hypotheses, i.e. it can be
-represented as `[Γ ⊢ A]`.
-
-The tactic monad naturally operates over the whole proofview, which may
-represent several goals, including none. Thus, there is no such thing as
-*the current goal*. Goals are naturally ordered, though.
-
-It is natural to do the same in Ltac2, but we must provide a way to get access
-to a given goal. This is the role of the `enter` primitive, that applies a
-tactic to each currently focused goal in turn.
-
-```
-val enter : (unit -> unit) -> unit
-```
-
-It is guaranteed that when evaluating `enter f`, `f` is called with exactly one
-goal under focus. Note that `f` may be called several times, or never, depending
-on the number of goals under focus before the call to `enter`.
-
-Accessing the goal data is then implicit in the Ltac2 primitives, and may panic
-if the invariants are not respected. The two essential functions for observing
-goals are given below.
-
-```
-val hyp : ident -> constr
-val goal : unit -> constr
-```
-
-The two above functions panic if there is not exactly one goal under focus.
-In addition, `hyp` may also fail if there is no hypothesis with the
-corresponding name.
-
-# Meta-programming
-
-## Overview
-
-One of the horrendous implementation issues of Ltac is the fact that it is
-never clear whether an object refers to the object world or the meta-world.
-This is an incredible source of slowness, as the interpretation must be
-aware of bound variables and must use heuristics to decide whether a variable
-is a proper one or referring to something in the Ltac context.
-
-Likewise, in Ltac1, constr parsing is implicit, so that `foo 0` is
-not `foo` applied to the Ltac integer expression `0` (Ltac does have a
-non-first-class notion of integers), but rather the Coq term `Datatypes.O`.
-
-We should stop doing that! We need to mark when quoting and unquoting, although
-we need to do that in a short and elegant way so as not to be too cumbersome
-to the user.
-
-## Generic Syntax for Quotations
-
-In general, quotations can be introduced in term by the following syntax, where
-`QUOTENTRY` is some parsing entry.
-```
-TERM ::=
-| QUOTNAME ":" "(" QUOTENTRY ")"
-
-QUOTNAME := IDENT
-```
-
-### Built-in quotations
-
-The current implementation recognizes the following built-in quotations:
-- "ident", which parses identifiers (type `Init.ident`).
-- "constr", which parses Coq terms and produces an-evar free term at runtime
- (type `Init.constr`).
-- "open_constr", which parses Coq terms and produces a term potentially with
- holes at runtime (type `Init.constr` as well).
-- "pattern", which parses Coq patterns and produces a pattern used for term
- matching (type `Init.pattern`).
-- "reference", which parses either a `QUALID` or `"&" IDENT`. Qualified names
- are globalized at internalization into the corresponding global reference,
- while `&id` is turned into `Std.VarRef id`. This produces at runtime a
- `Std.reference`.
-
-The following syntactic sugar is provided for two common cases.
-- `@id` is the same as ident:(id)
-- `'t` is the same as open_constr:(t)
-
-### Strict vs. non-strict mode
-
-Depending on the context, quotations producing terms (i.e. `constr` or
-`open_constr`) are not internalized in the same way. There are two possible
-modes, respectively called the *strict* and the *non-strict* mode.
-
-- In strict mode, all simple identifiers appearing in a term quotation are
-required to be resolvable statically. That is, they must be the short name of
-a declaration which is defined globally, excluding section variables and
-hypotheses. If this doesn't hold, internalization will fail. To work around
-this error, one has to specifically use the `&` notation.
-- In non-strict mode, any simple identifier appearing in a term quotation which
-is not bound in the global context is turned into a dynamic reference to a
-hypothesis. That is to say, internalization will succeed, but the evaluation
-of the term at runtime will fail if there is no such variable in the dynamic
-context.
-
-Strict mode is enforced by default, e.g. for all Ltac2 definitions. Non-strict
-mode is only set when evaluating Ltac2 snippets in interactive proof mode. The
-rationale is that it is cumbersome to explicitly add `&` interactively, while it
-is expected that global tactics enforce more invariants on their code.
-
-## Term Antiquotations
-
-### Syntax
-
-One can also insert Ltac2 code into Coq term, similarly to what was possible in
-Ltac1.
-
-```
-COQCONSTR ::=
-| "ltac2" ":" "(" TERM ")"
-```
-
-Antiquoted terms are expected to have type `unit`, as they are only evaluated
-for their side-effects.
-
-### Semantics
-
-Interpretation of a quoted Coq term is done in two phases, internalization and
-evaluation.
-
-- Internalization is part of the static semantics, i.e. it is done at Ltac2
- typing time.
-- Evaluation is part of the dynamic semantics, i.e. it is done when
- a term gets effectively computed by Ltac2.
-
-Remark that typing of Coq terms is a *dynamic* process occuring at Ltac2
-evaluation time, and not at Ltac2 typing time.
-
-#### Static semantics
-
-During internalization, Coq variables are resolved and antiquotations are
-type-checked as Ltac2 terms, effectively producing a `glob_constr` in Coq
-implementation terminology. Note that although it went through the
-type-checking of **Ltac2**, the resulting term has not been fully computed and
-is potentially ill-typed as a runtime **Coq** term.
-
-```
-Ltac2 Definition myconstr () := constr:(nat -> 0).
-// Valid with type `unit -> constr`, but will fail at runtime.
-```
-
-Term antiquotations are type-checked in the enclosing Ltac2 typing context
-of the corresponding term expression. For instance, the following will
-type-check.
-
-```
-let x := '0 in constr:(1 + ltac2:(exact x))
-// type constr
-```
-
-Beware that the typing environment of typing of antiquotations is **not**
-expanded by the Coq binders from the term. Namely, it means that the following
-Ltac2 expression will **not** type-check.
-```
-constr:(fun x : nat => ltac2:(exact x))
-// Error: Unbound variable 'x'
-```
-
-There is a simple reason for that, which is that the following expression would
-not make sense in general.
-```
-constr:(fun x : nat => ltac2:(clear @x; exact x))
-```
-Indeed, a hypothesis can suddenly disappear from the runtime context if some
-other tactic pulls the rug from under you.
-
-Rather, the tactic writer has to resort to the **dynamic** goal environment,
-and must write instead explicitly that she is accessing a hypothesis, typically
-as follows.
-```
-constr:(fun x : nat => ltac2:(exact (hyp @x)))
-```
-
-This pattern is so common that we provide dedicated Ltac2 and Coq term notations
-for it.
-
-- `&x` as an Ltac2 expression expands to `hyp @x`.
-- `&x` as a Coq constr expression expands to
- `ltac2:(Control.refine (fun () => hyp @x))`.
-
-#### Dynamic semantics
-
-During evaluation, a quoted term is fully evaluated to a kernel term, and is
-in particular type-checked in the current environment.
-
-Evaluation of a quoted term goes as follows.
-- The quoted term is first evaluated by the pretyper.
-- Antiquotations are then evaluated in a context where there is exactly one goal
-under focus, with the hypotheses coming from the current environment extended
-with the bound variables of the term, and the resulting term is fed into the
-quoted term.
-
-Relative orders of evaluation of antiquotations and quoted term are not
-specified.
-
-For instance, in the following example, `tac` will be evaluated in a context
-with exactly one goal under focus, whose last hypothesis is `H : nat`. The
-whole expression will thus evaluate to the term `fun H : nat => nat`.
-```
-let tac () := hyp @H in constr:(fun H : nat => ltac2:(tac ()))
-```
-
-Many standard tactics perform type-checking of their argument before going
-further. It is your duty to ensure that terms are well-typed when calling
-such tactics. Failure to do so will result in non-recoverable exceptions.
-
-## Trivial Term Antiquotations
-
-It is possible to refer to a variable of type `constr` in the Ltac2 environment
-through a specific syntax consistent with the antiquotations presented in
-the notation section.
-
-```
-COQCONSTR ::=
-| "$" LIDENT
-```
-
-In a Coq term, writing `$x` is semantically equivalent to
-`ltac2:(Control.refine (fun () => x))`, up to re-typechecking. It allows to
-insert in a concise way an Ltac2 variable of type `constr` into a Coq term.
-
-## Match over terms
-
-Ltac2 features a construction similar to Ltac1 `match` over terms, although
-in a less hard-wired way.
-
-```
-TERM ::=
-| "match!" TERM "with" CONSTR-MATCHING* "end"
-| "lazy_match!" TERM "with" CONSTR-MATCHING* "end"
-| "multi_match!" TERM "with" CONSTR-MATCHING*"end"
-
-CONSTR-MATCHING :=
-| "|" CONSTR-PATTERN "=>" TERM
-
-CONSTR-PATTERN :=
-| CONSTR
-| "context" LIDENT? "[" CONSTR "]"
-```
-
-This construction is not primitive and is desugared at parsing time into
-calls to term matching functions from the `Pattern` module. Internally, it is
-implemented thanks to a specific scope accepting the `CONSTR-MATCHING` syntax.
-
-Variables from the `CONSTR-PATTERN` are statically bound in the body of the branch, to
-values of type `constr` for the variables from the `CONSTR` pattern and to a
-value of type `Pattern.context` for the variable `LIDENT`.
-
-Note that contrarily to Ltac, only lowercase identifiers are valid as Ltac2
-bindings, so that there will be a syntax error if one of the bound variables
-starts with an uppercase character.
-
-The semantics of this construction is otherwise the same as the corresponding
-one from Ltac1, except that it requires the goal to be focused.
-
-## Match over goals
-
-Similarly, there is a way to match over goals in an elegant way, which is
-just a notation desugared at parsing time.
-
-```
-TERM ::=
-| "match!" MATCH-ORDER? "goal" "with" GOAL-MATCHING* "end"
-| "lazy_match!" MATCH-ORDER? "goal" "with" GOAL-MATCHING* "end"
-| "multi_match!" MATCH-ORDER? "goal" "with" GOAL-MATCHING*"end"
-
-GOAL-MATCHING :=
-| "|" "[" HYP-MATCHING* "|-" CONSTR-PATTERN "]" "=>" TERM
-
-HYP-MATCHING :=
-| LIDENT ":" CONSTR-PATTERN
-
-MATCH-ORDER :=
-| "reverse"
-```
-
-Variables from `HYP-MATCHING` and `CONSTR-PATTERN` are bound in the body of the
-branch. Their types are:
-- `constr` for pattern variables appearing in a `CONSTR`
-- `Pattern.context` for variables binding a context
-- `ident` for variables binding a hypothesis name.
-
-The same identifier caveat as in the case of matching over constr applies, and
-this features has the same semantics as in Ltac1. In particular, a `reverse`
-flag can be specified to match hypotheses from the more recently introduced to
-the least recently introduced one.
-
-# Notations
-
-Notations are the crux of the usability of Ltac1. We should be able to recover
-a feeling similar to the old implementation by using and abusing notations.
-
-## Scopes
-
-A scope is a name given to a grammar entry used to produce some Ltac2 expression
-at parsing time. Scopes are described using a form of S-expression.
-
-```
-SCOPE :=
-| STRING
-| INT
-| LIDENT ( "(" SCOPE₀ "," ... "," SCOPEₙ ")" )
-```
-
-A few scopes contain antiquotation features. For sake of uniformity, all
-antiquotations are introduced by the syntax `"$" VAR`.
-
-The following scopes are built-in.
-- constr:
- + parses `c = COQCONSTR` and produces `constr:(c)`
-- ident:
- + parses `id = IDENT` and produces `ident:(id)`
- + parses `"$" (x = IDENT)` and produces the variable `x`
-- list0(*scope*):
- + if *scope* parses `ENTRY`, parses ̀`(x₀, ..., xₙ = ENTRY*)` and produces
- `[x₀; ...; xₙ]`.
-- list0(*scope*, sep = STRING):
- + if *scope* parses `ENTRY`, parses `(x₀ = ENTRY, "sep", ..., "sep", xₙ = ENTRY)`
- and produces `[x₀; ...; xₙ]`.
-- list1: same as list0 (with or without separator) but parses `ENTRY+` instead
- of `ENTRY*`.
-- opt(*scope*)
- + if *scope* parses `ENTRY`, parses `ENTRY?` and produces either `None` or
- `Some x` where `x` is the parsed expression.
-- self:
- + parses a Ltac2 expression at the current level and return it as is.
-- next:
- + parses a Ltac2 expression at the next level and return it as is.
-- tactic(n = INT):
- + parses a Ltac2 expression at the provided level *n* and return it as is.
-- thunk(*scope*):
- + parses the same as *scope*, and if *e* is the parsed expression, returns
- `fun () => e`.
-- STRING:
- + parses the corresponding string as a CAMLP5 IDENT and returns `()`.
-- keyword(s = STRING):
- + parses the string *s* as a keyword and returns `()`.
-- terminal(s = STRING):
- + parses the string *s* as a keyword, if it is already a
- keyword, otherwise as an IDENT. Returns `()`.
-- seq(*scope₁*, ..., *scopeₙ*):
- + parses *scope₁*, ..., *scopeₙ* in this order, and produces a tuple made
- out of the parsed values in the same order. As an optimization, all
- subscopes of the form STRING are left out of the returned tuple, instead
- of returning a useless unit value. It is forbidden for the various
- subscopes to refer to the global entry using self of next.
-
-A few other specific scopes exist to handle Ltac1-like syntax, but their use is
-discouraged and they are thus not documented.
-
-For now there is no way to declare new scopes from Ltac2 side, but this is
-planned.
-
-## Notations
-
-The Ltac2 parser can be extended by syntactic notations.
-```
-VERNAC ::=
-| "Ltac2" "Notation" TOKEN+ LEVEL? ":=" TERM
-
-LEVEL := ":" INT
-
-TOKEN :=
-| VAR "(" SCOPE ")"
-| STRING
-```
-
-A Ltac2 notation adds a parsing rule to the Ltac2 grammar, which is expanded
-to the provided body where every token from the notation is let-bound to the
-corresponding generated expression.
-
-For instance, assume we perform:
-```
-Ltac2 Notation "foo" c(thunk(constr)) ids(list0(ident)) := Bar.f c ids.
-```
-Then the following expression
-```
-let y := @X in foo (nat -> nat) x $y
-```
-will expand at parsing time to
-```
-let y := @X in
-let c := fun () => constr:(nat -> nat) with ids := [@x; y] in Bar.f c ids
-```
-
-Beware that the order of evaluation of multiple let-bindings is not specified,
-so that you may have to resort to thunking to ensure that side-effects are
-performed at the right time.
-
-## Abbreviations
-
-There exists a special kind of notations, called abbreviations, that is designed
-so that it does not add any parsing rules. It is similar in spirit to Coq
-abbreviations, insofar as its main purpose is to give an absolute name to a
-piece of pure syntax, which can be transparently referred by this name as if it
-were a proper definition. Abbreviations are introduced by the following
-syntax.
-
-```
-VERNAC ::=
-| "Ltac2" "Notation" IDENT ":=" TERM
-```
-
-The abbreviation can then be manipulated just as a normal Ltac2 definition,
-except that it is expanded at internalization time into the given expression.
-Furthermore, in order to make this kind of construction useful in practice in
-an effectful language such as Ltac2, any syntactic argument to an abbreviation
-is thunked on-the-fly during its expansion.
-
-For instance, suppose that we define the following.
-```
-Ltac2 Notation foo := fun x => x ().
-```
-Then we have the following expansion at internalization time.
-```
-foo 0 ↦ (fun x => x ()) (fun _ => 0)
-```
-
-Note that abbreviations are not typechecked at all, and may result in typing
-errors after expansion.
-
-# Evaluation
-
-Ltac2 features a toplevel loop that can be used to evaluate expressions.
-
-```
-VERNAC ::=
-| "Ltac2" "Eval" TERM
-```
-
-This command evaluates the term in the current proof if there is one, or in the
-global environment otherwise, and displays the resulting value to the user
-together with its type. This function is pure in the sense that it does not
-modify the state of the proof, and in particular all side-effects are discarded.
-
-# Debug
-
-When the option `Ltac2 Backtrace` is set, toplevel failures will be printed with
-a backtrace.
-
-# Compatibility layer with Ltac1
-
-## Ltac1 from Ltac2
-
-### Simple API
-
-One can call Ltac1 code from Ltac2 by using the `ltac1` quotation. It parses
-a Ltac1 expression, and semantics of this quotation is the evaluation of the
-corresponding code for its side effects. In particular, in cannot return values,
-and the quotation has type `unit`.
-
-Beware, Ltac1 **cannot** access variables from the Ltac2 scope. One is limited
-to the use of standalone function calls.
-
-### Low-level API
-
-There exists a lower-level FFI into Ltac1 that is not recommended for daily use,
-which is available in the `Ltac2.Ltac1` module. This API allows to directly
-manipulate dynamically-typed Ltac1 values, either through the function calls,
-or using the `ltac1val` quotation. The latter parses the same as `ltac1`, but
-has type `Ltac2.Ltac1.t` instead of `unit`, and dynamically behaves as an Ltac1
-thunk, i.e. `ltac1val:(foo)` corresponds to the tactic closure that Ltac1
-would generate from `idtac; foo`.
-
-Due to intricate dynamic semantics, understanding when Ltac1 value quotations
-focus is very hard. This is why some functions return a continuation-passing
-style value, as it can dispatch dynamically between focused and unfocused
-behaviour.
-
-## Ltac2 from Ltac1
-
-Same as above by switching Ltac1 by Ltac2 and using the `ltac2` quotation
-instead.
-
-Note that the tactic expression is evaluated eagerly, if one wants to use it as
-an argument to a Ltac1 function, she has to resort to the good old
-`idtac; ltac2:(foo)` trick. For instance, the code below will fail immediately
-and won't print anything.
-
-```
-Ltac mytac tac := idtac "wow"; tac.
-
-Goal True.
-Proof.
-mytac ltac2:(fail).
-```
-
-# Transition from Ltac1
-
-Owing to the use of a bunch of notations, the transition shouldn't be
-atrociously horrible and shockingly painful up to the point you want to retire
-in the Ariège mountains, living off the land and insulting careless bypassers in
-proto-georgian.
-
-That said, we do *not* guarantee you it is going to be a blissful walk either.
-Hopefully, owing to the fact Ltac2 is typed, the interactive dialogue with Coq
-will help you.
-
-We list the major changes and the transition strategies hereafter.
-
-## Syntax changes
-
-Due to conflicts, a few syntactic rules have changed.
-
-- The dispatch tactical `tac; [foo|bar]` is now written `tac > [foo|bar]`.
-- Levels of a few operators have been revised. Some tacticals now parse as if
- they were a normal function, i.e. one has to put parentheses around the
- argument when it is complex, e.g an abstraction. List of affected tacticals:
- `try`, `repeat`, `do`, `once`, `progress`, `time`, `abstract`.
-- `idtac` is no more. Either use `()` if you expect nothing to happen,
- `(fun () => ())` if you want a thunk (see next section), or use printing
- primitives from the `Message` module if you want to display something.
-
-## Tactic delay
-
-Tactics are not magically delayed anymore, neither as functions nor as
-arguments. It is your responsibility to thunk them beforehand and apply them
-at the call site.
-
-A typical example of a delayed function:
-```
-Ltac foo := blah.
-```
-becomes
-```
-Ltac2 foo () := blah.
-```
-
-All subsequent calls to `foo` must be applied to perform the same effect as
-before.
-
-Likewise, for arguments:
-```
-Ltac bar tac := tac; tac; tac.
-```
-becomes
-```
-Ltac2 bar tac := tac (); tac (); tac ().
-```
-
-We recommend the use of syntactic notations to ease the transition. For
-instance, the first example can alternatively written as:
-```
-Ltac2 foo0 () := blah.
-Ltac2 Notation foo := foo0 ().
-```
-
-This allows to keep the subsequent calls to the tactic as-is, as the
-expression `foo` will be implicitly expanded everywhere into `foo0 ()`. Such
-a trick also works for arguments, as arguments of syntactic notations are
-implicitly thunked. The second example could thus be written as follows.
-
-```
-Ltac2 bar0 tac := tac (); tac (); tac ().
-Ltac2 Notation bar := bar0.
-```
-
-## Variable binding
-
-Ltac1 relies on a crazy amount of dynamic trickery to be able to tell apart
-bound variables from terms, hypotheses and whatnot. There is no such thing in
-Ltac2, as variables are recognized statically and other constructions do not
-live in the same syntactic world. Due to the abuse of quotations, it can
-sometimes be complicated to know what a mere identifier represents in a tactic
-expression. We recommend tracking the context and letting the compiler spit
-typing errors to understand what is going on.
-
-We list below the typical changes one has to perform depending on the static
-errors produced by the typechecker.
-
-### In Ltac expressions
-
-- `Unbound value X`, `Unbound constructor X`:
- * if `X` is meant to be a term from the current stactic environment, replace
- the problematic use by `'X`.
- * if `X` is meant to be a hypothesis from the goal context, replace the
- problematic use by `&X`.
-
-### In quotations
-
-- `The reference X was not found in the current environment`:
- * if `X` is meant to be a tactic expression bound by a Ltac2 let or function,
- replace the problematic use by `$X`.
- * if `X` is meant to be a hypothesis from the goal context, replace the
- problematic use by `&X`.
-
-## Exception catching
-
-Ltac2 features a proper exception-catching mechanism. For this reason, the
-Ltac1 mechanism relying on `fail` taking integers and tacticals decreasing it
-has been removed. Now exceptions are preserved by all tacticals, and it is
-your duty to catch it and reraise it depending on your use.
-
-# TODO
-
-- Implement deep pattern-matching.
-- Craft an expressive set of primitive functions
-- Implement native compilation to OCaml