diff options
117 files changed, 3896 insertions, 4708 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml index 352ec5a51..00db64f26 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -31,11 +31,11 @@ before_script: &before_script source ~/.profile printenv if [ -n "${EXTRA_PACKAGES}" ]; then sudo apt-get update -yq && sudo apt-get install -yq --no-install-recommends ${EXTRA_PACKAGES}; fi + echo . ~/.profile >> $BASH_ENV opam-switch: &opam-switch name: Select opam switch command: | - source ~/.profile opam switch ${COMPILER} opam config list opam list @@ -48,7 +48,6 @@ opam-switch: &opam-switch - run: name: Cache selection command: | - source ~/.profile # We can't use environment variables in cache names # So put it in a file and use the checksum echo "$COMPILER" > COMPILER @@ -59,19 +58,16 @@ opam-switch: &opam-switch - run: name: Update opam lists command: | - source ~/.profile opam repository set-url default https://opam.ocaml.org opam update - run: name: Install opam packages command: | - source ~/.profile opam switch -j ${NJOBS} ${COMPILER} opam install -j ${NJOBS} -y camlp5.${CAMLP5_VER} ocamlfind ${EXTRA_OPAM} - run: name: Clean cache command: | - source ~/.profile rm -rf ~/.opam/log/ - save_cache: key: coq-opam-cache-v1-{{ arch }}-{{ checksum "COMPILER" }}-{{ checksum ".circleci/config.yml" }}- @@ -93,13 +89,10 @@ opam-switch: &opam-switch - run: &build-configure name: Configure command: | - source ~/.profile - ./configure -local -native-compiler ${NATIVE_COMP} -coqide no - run: &build-build name: Build command: | - source ~/.profile make -j ${NJOBS} byte make -j ${NJOBS} make test-suite/misc/universes/all_stdlib.v @@ -118,7 +111,6 @@ opam-switch: &opam-switch - run: name: Test command: | - source ~/.profile dev/ci/ci-wrapper.sh ${CIRCLE_JOB} - persist_to_workspace: root: *workspace @@ -99,6 +99,7 @@ Tactics of the execution. - `vm_compute` now supports existential variables. - Calls to `shelve` and `give_up` within calls to tactic `refine` now working. +- Deprecated tactic `appcontext` was removed. Focusing @@ -202,6 +203,7 @@ Options + `Refolding Reduction` + `Standard Proposition Elimination` + + `Dependent Propositions Elimination` + `Discriminate Introduction` + `Shrink Abstract` + `Tactic Pattern Unification` @@ -209,6 +211,7 @@ Options + `Injection L2R Pattern Order` + `Record Elimination Schemes` + `Match Strict` + + `Tactic Compat Context` + `Typeclasses Legacy Resolution` + `Typeclasses Module Eta` + `Typeclass Resolution After Apply` @@ -128,6 +128,8 @@ of the Coq Proof assistant during the indicated time: Matej Košík (INRIA, 2015-2017) Pierre Letouzey (LRI, 2000-2004, PPS, 2005-2008, INRIA-PPS then IRIF, 2009-now) + Yishuai Li (ORCID: https://orcid.org/0000-0002-5728-5903 + U. Penn, 2018) Patrick Loiseleur (Paris Sud, 1997-1999) Evgeny Makarov (INRIA, 2007) Gregory Malecha (Harvard University 2013-2015, diff --git a/Makefile.doc b/Makefile.doc index b9443f723..dc2b9f55d 100644 --- a/Makefile.doc +++ b/Makefile.doc @@ -56,9 +56,7 @@ ALLSPHINXOPTS= -d $(SPHINXBUILDDIR)/doctrees $(SPHINXOPTS) DOCCOMMON:=doc/common/version.tex doc/common/title.tex doc/common/macros.tex -REFMANCOQTEXFILES:=$(addprefix doc/refman/, \ - RefMan-gal.v.tex \ - RefMan-ltac.v.tex) +REFMANCOQTEXFILES:=$(addprefix doc/refman/, ) REFMANTEXFILES:=$(addprefix doc/refman/, \ headers.sty Reference-Manual.tex) \ @@ -84,7 +82,7 @@ doc: sphinx refman tutorial rectutorial stdlib $(INDEXURLS) sphinx: coq $(SHOW)'SPHINXBUILD doc/sphinx' - $(HIDE)COQBIN="$(PWD)/bin" $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) doc/sphinx $(SPHINXBUILDDIR)/html + $(HIDE)COQBIN="$(PWD)/bin" $(SPHINXBUILD) -W -b html $(ALLSPHINXOPTS) doc/sphinx $(SPHINXBUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(SPHINXBUILDDIR)/html." diff --git a/dev/ci/user-overlays/06454-ejgallego-evar+strict_to_constr.sh b/dev/ci/user-overlays/06454-ejgallego-evar+strict_to_constr.sh new file mode 100644 index 000000000..f4cb71cf1 --- /dev/null +++ b/dev/ci/user-overlays/06454-ejgallego-evar+strict_to_constr.sh @@ -0,0 +1,8 @@ +if [ "$CI_PULL_REQUEST" = "6454" ] || [ "$CI_BRANCH" = "evar+strict_to_constr" ]; then + + # ltac2_CI_BRANCH=econstr+more_fix + # ltac2_CI_GITURL=https://github.com/ejgallego/ltac2 + + Equations_CI_BRANCH=evar+strict_to_constr + Equations_CI_GITURL=https://github.com/ejgallego/Coq-Equations +fi diff --git a/dev/ci/user-overlays/07136-evar-map-econstr.sh b/dev/ci/user-overlays/07136-evar-map-econstr.sh new file mode 100644 index 000000000..06aa62726 --- /dev/null +++ b/dev/ci/user-overlays/07136-evar-map-econstr.sh @@ -0,0 +1,7 @@ +if [ "$CI_PULL_REQUEST" = "7136" ] || [ "$CI_BRANCH" = "evar-map-econstr" ]; then + Equations_CI_BRANCH=8.9+alpha + Equations_CI_GITURL=https://github.com/SkySkimmer/Coq-Equations.git + + Elpi_CI_BRANCH=coq-7136 + Elpi_CI_GITURL=https://github.com/SkySkimmer/coq-elpi.git +fi diff --git a/dev/doc/changes.md b/dev/doc/changes.md index ab78b0956..1a24f23e5 100644 --- a/dev/doc/changes.md +++ b/dev/doc/changes.md @@ -1,3 +1,12 @@ +## Changes between Coq 8.8 and Coq 8.9 + +### ML API + +Proof engine + + More functions have been changed to use `EConstr`, notably the + functions in `Evd`. + ## Changes between Coq 8.7 and Coq 8.8 ### Bug tracker diff --git a/dev/top_printers.ml b/dev/top_printers.ml index ba0c54407..f9b402586 100644 --- a/dev/top_printers.ml +++ b/dev/top_printers.ml @@ -181,7 +181,7 @@ let ppproofview p = pp(pr_enum Goal.pr_goal gls ++ fnl () ++ Termops.pr_evar_map (Some 1) sigma) let ppopenconstr (x : Evd.open_constr) = - let (evd,c) = x in pp (Termops.pr_evar_map (Some 2) evd ++ envpp pr_constr_env c) + let (evd,c) = x in pp (Termops.pr_evar_map (Some 2) evd ++ envpp pr_econstr_env c) (* spiwack: deactivated until a replacement is found let pppftreestate p = pp(print_pftreestate p) *) diff --git a/doc/LICENSE b/doc/LICENSE index 7ae31b089..c223a4e16 100644 --- a/doc/LICENSE +++ b/doc/LICENSE @@ -2,15 +2,17 @@ The Coq Reference Manual is a collective work from the Coq Development Team whose members are listed in the file CREDITS of the Coq source package. All related documents (the LaTeX and BibTeX sources, the embedded png files, and the PostScript, PDF and html outputs) are -copyright (c) INRIA 1999-2006, with the exception of the Ubuntu font files -(UbuntuMono-Square.ttf and UbuntuMono-B.ttf), derived from UbuntuMono-Regular, -which is Copyright 2010,2011 Canonical Ltd and licensed under the Ubuntu font +copyright (c) INRIA 1999-2006, with the exception of the Ubuntu font +file UbuntuMono-B.ttf, which is +Copyright 2010,2011 Canonical Ltd and licensed under the Ubuntu font license, version 1.0 -(https://www.ubuntu.com/legal/terms-and-policies/font-licence). The material -connected to the Reference Manual may be distributed only subject to the terms -and conditions set forth in the Open Publication License, v1.0 or later (the -latest version is presently available at http://www.opencontent.org/openpub/). -Options A and B are *not* elected. +(https://www.ubuntu.com/legal/terms-and-policies/font-licence), and its +derivative CoqNotations.ttf distributed under the same license. The +material connected to the Reference Manual may be distributed only +subject to the terms and conditions set forth in the Open Publication +License, v1.0 or later (the latest version is presently available at +http://www.opencontent.org/openpub/). Options A and B are *not* +elected. The Coq Tutorial is a work by Gérard Huet, Gilles Kahn and Christine Paulin-Mohring. All documents (the LaTeX source and the PostScript, diff --git a/doc/refman/RefMan-gal.tex b/doc/refman/RefMan-gal.tex deleted file mode 100644 index 41ea0a5dc..000000000 --- a/doc/refman/RefMan-gal.tex +++ /dev/null @@ -1,1737 +0,0 @@ -\chapter{The \gallina{} specification language -\label{Gallina}\index{Gallina}} -%HEVEA\cutname{gallina.html} -\label{BNF-syntax} % Used referred to as a chapter label - -This chapter describes \gallina, the specification language of {\Coq}. -It allows developing mathematical theories and proofs of specifications -of programs. The theories are built from axioms, hypotheses, -parameters, lemmas, theorems and definitions of constants, functions, -predicates and sets. The syntax of logical objects involved in -theories is described in Section~\ref{term}. The language of -commands, called {\em The Vernacular} is described in section -\ref{Vernacular}. - -In {\Coq}, logical objects are typed to ensure their logical -correctness. The rules implemented by the typing algorithm are described in -Chapter \ref{Cic}. - -\subsection*{About the grammars in the manual -\index{BNF metasyntax}} - -Grammars are presented in Backus-Naur form (BNF). Terminal symbols are -set in {\tt typewriter font}. In addition, there are special -notations for regular expressions. - -An expression enclosed in square brackets \zeroone{\ldots} means at -most one occurrence of this expression (this corresponds to an -optional component). - -The notation ``\nelist{\entry}{sep}'' stands for a non empty -sequence of expressions parsed by {\entry} and -separated by the literal ``{\tt sep}''\footnote{This is similar to the -expression ``{\entry} $\{$ {\tt sep} {\entry} $\}$'' in -standard BNF, or ``{\entry}~{$($} {\tt sep} {\entry} {$)$*}'' in -the syntax of regular expressions.}. - -Similarly, the notation ``\nelist{\entry}{}'' stands for a non -empty sequence of expressions parsed by the ``{\entry}'' entry, -without any separator between. - -Finally, the notation ``\sequence{\entry}{\tt sep}'' stands for a -possibly empty sequence of expressions parsed by the ``{\entry}'' entry, -separated by the literal ``{\tt sep}''. - -\section{Lexical conventions -\label{lexical}\index{Lexical conventions}} - -\paragraph{Blanks} -Space, newline and horizontal tabulation are considered as blanks. -Blanks are ignored but they separate tokens. - -\paragraph{Comments} - -Comments in {\Coq} are enclosed between {\tt (*} and {\tt - *)}\index{Comments}, and can be nested. They can contain any -character. However, string literals must be correctly closed. Comments -are treated as blanks. - -\paragraph{Identifiers and access identifiers} - -Identifiers, written {\ident}, are sequences of letters, digits, -\verb!_! and \verb!'!, that do not start with a digit or \verb!'!. -That is, they are recognized by the following lexical class: - -\index{ident@\ident} -\begin{center} -\begin{tabular}{rcl} -{\firstletter} & ::= & {\tt a..z} $\mid$ {\tt A..Z} $\mid$ {\tt \_} -$\mid$ {\tt unicode-letter} -\\ -{\subsequentletter} & ::= & {\tt a..z} $\mid$ {\tt A..Z} $\mid$ {\tt 0..9} -$\mid$ {\tt \_} % $\mid$ {\tt \$} -$\mid$ {\tt '} -$\mid$ {\tt unicode-letter} -$\mid$ {\tt unicode-id-part} \\ -{\ident} & ::= & {\firstletter} \sequencewithoutblank{\subsequentletter}{} -\end{tabular} -\end{center} -All characters are meaningful. In particular, identifiers are -case-sensitive. The entry {\tt unicode-letter} non-exhaustively -includes Latin, Greek, Gothic, Cyrillic, Arabic, Hebrew, Georgian, -Hangul, Hiragana and Katakana characters, CJK ideographs, mathematical -letter-like symbols, hyphens, non-breaking space, {\ldots} The entry -{\tt unicode-id-part} non-exhaustively includes symbols for prime -letters and subscripts. - -Access identifiers, written {\accessident}, are identifiers prefixed -by \verb!.! (dot) without blank. They are used in the syntax of qualified -identifiers. - -\paragraph{Natural numbers and integers} -Numerals are sequences of digits. Integers are numerals optionally preceded by a minus sign. - -\index{num@{\num}} -\index{integer@{\integer}} -\begin{center} -\begin{tabular}{r@{\quad::=\quad}l} -{\digit} & {\tt 0..9} \\ -{\num} & \nelistwithoutblank{\digit}{} \\ -{\integer} & \zeroone{\tt -}{\num} \\ -\end{tabular} -\end{center} - -\paragraph[Strings]{Strings\label{strings} -\index{string@{\qstring}}} -Strings are delimited by \verb!"! (double quote), and enclose a -sequence of any characters different from \verb!"! or the sequence -\verb!""! to denote the double quote character. In grammars, the -entry for quoted strings is {\qstring}. - -\paragraph{Keywords} -The following identifiers are reserved keywords, and cannot be -employed otherwise: -\begin{center} -\begin{tabular}{llllll} -\verb!_! & -\verb!as! & -\verb!at! & -\verb!cofix! & -\verb!else! & -\verb!end! \\ -% -\verb!exists! & -\verb!exists2! & -\verb!fix! & -\verb!for! & -\verb!forall! & -\verb!fun! \\ -% -\verb!if! & -\verb!IF! & -\verb!in! & -\verb!let! & -\verb!match! & -\verb!mod! \\ -% -\verb!Prop! & -\verb!return! & -\verb!Set! & -\verb!then! & -\verb!Type! & -\verb!using! \\ -% -\verb!where! & -\verb!with! & -\end{tabular} -\end{center} - - -\paragraph{Special tokens} -The following sequences of characters are special tokens: -\begin{center} -\begin{tabular}{lllllll} -\verb/!/ & -\verb!%! & -\verb!&! & -\verb!&&! & -\verb!(! & -\verb!()! & -\verb!)! \\ -% -\verb!*! & -\verb!+! & -\verb!++! & -\verb!,! & -\verb!-! & -\verb!->! & -\verb!.! \\ -% -\verb!.(! & -\verb!..! & -\verb!/! & -\verb!/\! & -\verb!:! & -\verb!::! & -\verb!:<! \\ -% -\verb!:=! & -\verb!:>! & -\verb!;! & -\verb!<! & -\verb!<-! & -\verb!<->! & -\verb!<:! \\ -% -\verb!<=! & -\verb!<>! & -\verb!=! & -\verb!=>! & -\verb!=_D! & -\verb!>! & -\verb!>->! \\ -% -\verb!>=! & -\verb!?! & -\verb!?=! & -\verb!@! & -\verb![! & -\verb!\/! & -\verb!]! \\ -% -\verb!^! & -\verb!{! & -\verb!|! & -\verb!|-! & -\verb!||! & -\verb!}! & -\verb!~! \\ -\end{tabular} -\end{center} - -Lexical ambiguities are resolved according to the ``longest match'' -rule: when a sequence of non alphanumerical characters can be decomposed -into several different ways, then the first token is the longest -possible one (among all tokens defined at this moment), and so on. - -\section{Terms \label{term}\index{Terms}} - -\subsection{Syntax of terms} - -Figures \ref{term-syntax} and \ref{term-syntax-aux} describe the basic syntax of -the terms of the {\em Calculus of Inductive Constructions} (also -called \CIC). The formal presentation of {\CIC} is given in Chapter -\ref{Cic}. Extensions of this syntax are given in chapter -\ref{Gallina-extension}. How to customize the syntax is described in Chapter -\ref{Addoc-syntax}. - -\begin{figure}[htbp] -\begin{centerframe} -\begin{tabular}{lcl@{\quad~}r} % warning: page width exceeded with \qquad -{\term} & ::= & - {\tt forall} {\binders} {\tt ,} {\term} &(\ref{products})\\ - & $|$ & {\tt fun} {\binders} {\tt =>} {\term} &(\ref{abstractions})\\ - & $|$ & {\tt fix} {\fixpointbodies} &(\ref{fixpoints})\\ - & $|$ & {\tt cofix} {\cofixpointbodies} &(\ref{fixpoints})\\ - & $|$ & {\tt let} {\ident} \zeroone{\binders} {\typecstr} {\tt :=} {\term} - {\tt in} {\term} &(\ref{let-in})\\ - & $|$ & {\tt let fix} {\fixpointbody} {\tt in} {\term} &(\ref{fixpoints})\\ - & $|$ & {\tt let cofix} {\cofixpointbody} - {\tt in} {\term} &(\ref{fixpoints})\\ - & $|$ & {\tt let} {\tt (} \sequence{\name}{,} {\tt )} \zeroone{\ifitem} - {\tt :=} {\term} - {\tt in} {\term} &(\ref{caseanalysis}, \ref{Mult-match})\\ - & $|$ & {\tt let '} {\pattern} \zeroone{{\tt in} {\term}} {\tt :=} {\term} - \zeroone{\returntype} {\tt in} {\term} & (\ref{caseanalysis}, \ref{Mult-match})\\ - & $|$ & {\tt if} {\term} \zeroone{\ifitem} {\tt then} {\term} - {\tt else} {\term} &(\ref{caseanalysis}, \ref{Mult-match})\\ - & $|$ & {\term} {\tt :} {\term} &(\ref{typecast})\\ - & $|$ & {\term} {\tt <:} {\term} &(\ref{typecast})\\ - & $|$ & {\term} {\tt :>} &(\ref{ProgramSyntax})\\ - & $|$ & {\term} {\tt ->} {\term} &(\ref{products})\\ - & $|$ & {\term} \nelist{\termarg}{}&(\ref{applications})\\ - & $|$ & {\tt @} {\qualid} \sequence{\term}{} - &(\ref{Implicits-explicitation})\\ - & $|$ & {\term} {\tt \%} {\ident} &(\ref{scopechange})\\ - & $|$ & {\tt match} \nelist{\caseitem}{\tt ,} - \zeroone{\returntype} {\tt with} &\\ - && ~~~\zeroone{\zeroone{\tt |} \nelist{\eqn}{|}} {\tt end} - &(\ref{caseanalysis})\\ - & $|$ & {\qualid} &(\ref{qualid})\\ - & $|$ & {\sort} &(\ref{Gallina-sorts})\\ - & $|$ & {\num} &(\ref{numerals})\\ - & $|$ & {\_} &(\ref{hole})\\ - & $|$ & {\tt (} {\term} {\tt )} & \\ - & & &\\ -{\termarg} & ::= & {\term} &\\ - & $|$ & {\tt (} {\ident} {\tt :=} {\term} {\tt )} - &(\ref{Implicits-explicitation})\\ -%% & $|$ & {\tt (} {\num} {\tt :=} {\term} {\tt )} -%% &(\ref{Implicits-explicitation})\\ -&&&\\ -{\binders} & ::= & \nelist{\binder}{} \\ -&&&\\ -{\binder} & ::= & {\name} & (\ref{Binders}) \\ - & $|$ & {\tt (} \nelist{\name}{} {\tt :} {\term} {\tt )} &\\ - & $|$ & {\tt (} {\name} {\typecstr} {\tt :=} {\term} {\tt )} &\\ - & $|$ & {\tt '} {\pattern} &\\ -& & &\\ -{\name} & ::= & {\ident} &\\ - & $|$ & {\tt \_} &\\ -&&&\\ -{\qualid} & ::= & {\ident} & \\ - & $|$ & {\qualid} {\accessident} &\\ - & & &\\ -{\sort} & ::= & {\tt Prop} ~$|$~ {\tt Set} ~$|$~ {\tt Type} & -\end{tabular} -\end{centerframe} -\caption{Syntax of terms} -\label{term-syntax} -\index{term@{\term}} -\index{sort@{\sort}} -\end{figure} - - - -\begin{figure}[htb] -\begin{centerframe} -\begin{tabular}{lcl} -{\fixpointbodies} & ::= & - {\fixpointbody} \\ - & $|$ & {\fixpointbody} {\tt with} \nelist{\fixpointbody}{{\tt with}} - {\tt for} {\ident} \\ -{\cofixpointbodies} & ::= & - {\cofixpointbody} \\ - & $|$ & {\cofixpointbody} {\tt with} \nelist{\cofixpointbody}{{\tt with}} - {\tt for} {\ident} \\ -&&\\ -{\fixpointbody} & ::= & - {\ident} {\binders} \zeroone{\annotation} {\typecstr} - {\tt :=} {\term} \\ -{\cofixpointbody} & ::= & {\ident} \zeroone{\binders} {\typecstr} {\tt :=} {\term} \\ - & &\\ -{\annotation} & ::= & {\tt \{ struct} {\ident} {\tt \}} \\ -&&\\ -{\caseitem} & ::= & {\term} \zeroone{{\tt as} \name} - \zeroone{{\tt in} \qualid \sequence{\pattern}{}} \\ -&&\\ -{\ifitem} & ::= & \zeroone{{\tt as} {\name}} {\returntype} \\ -&&\\ -{\returntype} & ::= & {\tt return} {\term} \\ -&&\\ -{\eqn} & ::= & \nelist{\multpattern}{\tt |} {\tt =>} {\term}\\ -&&\\ -{\multpattern} & ::= & \nelist{\pattern}{\tt ,}\\ -&&\\ -{\pattern} & ::= & {\qualid} \nelist{\pattern}{} \\ - & $|$ & {\tt @} {\qualid} \nelist{\pattern}{} \\ - - & $|$ & {\pattern} {\tt as} {\ident} \\ - & $|$ & {\pattern} {\tt \%} {\ident} \\ - & $|$ & {\qualid} \\ - & $|$ & {\tt \_} \\ - & $|$ & {\num} \\ - & $|$ & {\tt (} \nelist{\orpattern}{,} {\tt )} \\ -\\ -{\orpattern} & ::= & \nelist{\pattern}{\tt |}\\ -\end{tabular} -\end{centerframe} -\caption{Syntax of terms (continued)} -\label{term-syntax-aux} -\end{figure} - - -%%%%%%% - -\subsection{Types} - -{\Coq} terms are typed. {\Coq} types are recognized by the same -syntactic class as {\term}. We denote by {\type} the semantic subclass -of types inside the syntactic class {\term}. -\index{type@{\type}} - - -\subsection{Qualified identifiers and simple identifiers -\label{qualid} -\label{ident}} - -{\em Qualified identifiers} ({\qualid}) denote {\em global constants} -(definitions, lemmas, theorems, remarks or facts), {\em global -variables} (parameters or axioms), {\em inductive -types} or {\em constructors of inductive types}. -{\em Simple identifiers} (or shortly {\ident}) are a -syntactic subset of qualified identifiers. Identifiers may also -denote local {\em variables}, what qualified identifiers do not. - -\subsection{Numerals -\label{numerals}} - -Numerals have no definite semantics in the calculus. They are mere -notations that can be bound to objects through the notation mechanism -(see Chapter~\ref{Addoc-syntax} for details). Initially, numerals are -bound to Peano's representation of natural numbers -(see~\ref{libnats}). - -Note: negative integers are not at the same level as {\num}, for this -would make precedence unnatural. - -\subsection{Sorts -\index{Sorts} -\index{Type@{\Type}} -\index{Set@{\Set}} -\index{Prop@{\Prop}} -\index{Sorts} -\label{Gallina-sorts}} - -There are three sorts \Set, \Prop\ and \Type. -\begin{itemize} -\item \Prop\ is the universe of {\em logical propositions}. -The logical propositions themselves are typing the proofs. -We denote propositions by {\form}. This constitutes a semantic -subclass of the syntactic class {\term}. -\index{form@{\form}} -\item \Set\ is is the universe of {\em program -types} or {\em specifications}. -The specifications themselves are typing the programs. -We denote specifications by {\specif}. This constitutes a semantic -subclass of the syntactic class {\term}. -\index{specif@{\specif}} -\item {\Type} is the type of {\Set} and {\Prop} -\end{itemize} -\noindent More on sorts can be found in Section~\ref{Sorts}. - -\subsection{Binders -\label{Binders} -\index{binders}} - -Various constructions such as {\tt fun}, {\tt forall}, {\tt fix} and -{\tt cofix} {\em bind} variables. A binding is represented by an -identifier. If the binding variable is not used in the expression, the -identifier can be replaced by the symbol {\tt \_}. When the type of a -bound variable cannot be synthesized by the system, it can be -specified with the notation {\tt (}\,{\ident}\,{\tt :}\,{\type}\,{\tt -)}. There is also a notation for a sequence of binding variables -sharing the same type: {\tt (}\,{\ident$_1$}\ldots{\ident$_n$}\,{\tt -:}\,{\type}\,{\tt )}. A binder can also be any pattern prefixed by a quote, -e.g. {\tt '(x,y)}. - -Some constructions allow the binding of a variable to value. This is -called a ``let-binder''. The entry {\binder} of the grammar accepts -either an assumption binder as defined above or a let-binder. -The notation in the -latter case is {\tt (}\,{\ident}\,{\tt :=}\,{\term}\,{\tt )}. In a -let-binder, only one variable can be introduced at the same -time. It is also possible to give the type of the variable as follows: -{\tt (}\,{\ident}\,{\tt :}\,{\term}\,{\tt :=}\,{\term}\,{\tt )}. - -Lists of {\binder} are allowed. In the case of {\tt fun} and {\tt - forall}, it is intended that at least one binder of the list is an -assumption otherwise {\tt fun} and {\tt forall} gets identical. Moreover, -parentheses can be omitted in the case of a single sequence of -bindings sharing the same type (e.g.: {\tt fun~(x~y~z~:~A)~=>~t} can -be shortened in {\tt fun~x~y~z~:~A~=>~t}). - -\subsection{Abstractions -\label{abstractions} -\index{abstractions}} -\index{fun@{{\tt fun \ldots => \ldots}}} - -The expression ``{\tt fun} {\ident} {\tt :} {\type} {\tt =>}~{\term}'' -defines the {\em abstraction} of the variable {\ident}, of type -{\type}, over the term {\term}. It denotes a function of the variable -{\ident} that evaluates to the expression {\term} (e.g. {\tt fun x:$A$ -=> x} denotes the identity function on type $A$). -% The variable {\ident} is called the {\em parameter} of the function -% (we sometimes say the {\em formal parameter}). -The keyword {\tt fun} can be followed by several binders as given in -Section~\ref{Binders}. Functions over several variables are -equivalent to an iteration of one-variable functions. For instance the -expression ``{\tt fun}~{\ident$_{1}$}~{\ldots}~{\ident$_{n}$}~{\tt -:}~\type~{\tt =>}~{\term}'' denotes the same function as ``{\tt -fun}~{\ident$_{1}$}~{\tt :}~\type~{\tt =>}~{\ldots}~{\tt -fun}~{\ident$_{n}$}~{\tt :}~\type~{\tt =>}~{\term}''. If a let-binder -occurs in the list of binders, it is expanded to a let-in definition -(see Section~\ref{let-in}). - -\subsection{Products -\label{products} -\index{products}} -\index{forall@{{\tt forall \ldots, \ldots}}} - -The expression ``{\tt forall}~{\ident}~{\tt :}~{\type}{\tt -,}~{\term}'' denotes the {\em product} of the variable {\ident} of -type {\type}, over the term {\term}. As for abstractions, {\tt forall} -is followed by a binder list, and products over several variables are -equivalent to an iteration of one-variable products. -Note that {\term} is intended to be a type. - -If the variable {\ident} occurs in {\term}, the product is called {\em -dependent product}. The intention behind a dependent product {\tt -forall}~$x$~{\tt :}~{$A$}{\tt ,}~{$B$} is twofold. It denotes either -the universal quantification of the variable $x$ of type $A$ in the -proposition $B$ or the functional dependent product from $A$ to $B$ (a -construction usually written $\Pi_{x:A}.B$ in set theory). - -Non dependent product types have a special notation: ``$A$ {\tt ->} -$B$'' stands for ``{\tt forall \_:}$A${\tt ,}~$B$''. The {\em non dependent -product} is used both to denote the propositional implication and -function types. - -\subsection{Applications -\label{applications} -\index{applications}} - -The expression \term$_0$ \term$_1$ denotes the application of -\term$_0$ to \term$_1$. - -The expression {\tt }\term$_0$ \term$_1$ ... \term$_n${\tt} -denotes the application of the term \term$_0$ to the arguments -\term$_1$ ... then \term$_n$. It is equivalent to {\tt (} {\ldots} -{\tt (} {\term$_0$} {\term$_1$} {\tt )} {\ldots} {\tt )} {\term$_n$} {\tt }: -associativity is to the left. - -The notation {\tt (}\,{\ident}\,{\tt :=}\,{\term}\,{\tt )} for -arguments is used for making explicit the value of implicit arguments -(see Section~\ref{Implicits-explicitation}). - -\subsection{Type cast -\label{typecast} -\index{Cast}} -\index{cast@{{\tt(\ldots: \ldots)}}} - -The expression ``{\term}~{\tt :}~{\type}'' is a type cast -expression. It enforces the type of {\term} to be {\type}. - -``{\term}~{\tt <:}~{\type}'' locally sets up the virtual machine for checking -that {\term} has type {\type}. - -\subsection{Inferable subterms -\label{hole} -\index{\_}} - -Expressions often contain redundant pieces of information. Subterms that -can be automatically inferred by {\Coq} can be replaced by the -symbol ``\_'' and {\Coq} will guess the missing piece of information. - -\subsection{Let-in definitions -\label{let-in} -\index{Let-in definitions} -\index{let-in}} -\index{let@{{\tt let \ldots := \ldots in \ldots}}} - - -{\tt let}~{\ident}~{\tt :=}~{\term$_1$}~{\tt in}~{\term$_2$} denotes -the local binding of \term$_1$ to the variable $\ident$ in -\term$_2$. -There is a syntactic sugar for let-in definition of functions: {\tt -let} {\ident} {\binder$_1$} {\ldots} {\binder$_n$} {\tt :=} {\term$_1$} -{\tt in} {\term$_2$} stands for {\tt let} {\ident} {\tt := fun} -{\binder$_1$} {\ldots} {\binder$_n$} {\tt =>} {\term$_1$} {\tt in} -{\term$_2$}. - -\subsection{Definition by case analysis -\label{caseanalysis} -\index{match@{\tt match\ldots with\ldots end}}} - -Objects of inductive types can be destructurated by a case-analysis -construction called {\em pattern-matching} expression. A -pattern-matching expression is used to analyze the structure of an -inductive objects and to apply specific treatments accordingly. - -This paragraph describes the basic form of pattern-matching. See -Section~\ref{Mult-match} and Chapter~\ref{Mult-match-full} for the -description of the general form. The basic form of pattern-matching is -characterized by a single {\caseitem} expression, a {\multpattern} -restricted to a single {\pattern} and {\pattern} restricted to the -form {\qualid} \nelist{\ident}{}. - -The expression {\tt match} {\term$_0$} {\returntype} {\tt with} -{\pattern$_1$} {\tt =>} {\term$_1$} {\tt $|$} {\ldots} {\tt $|$} -{\pattern$_n$} {\tt =>} {\term$_n$} {\tt end}, denotes a {\em -pattern-matching} over the term {\term$_0$} (expected to be of an -inductive type $I$). The terms {\term$_1$}\ldots{\term$_n$} are the -{\em branches} of the pattern-matching expression. Each of -{\pattern$_i$} has a form \qualid~\nelist{\ident}{} where {\qualid} -must denote a constructor. There should be exactly one branch for -every constructor of $I$. - -The {\returntype} expresses the type returned by the whole {\tt match} -expression. There are several cases. In the {\em non dependent} case, -all branches have the same type, and the {\returntype} is the common -type of branches. In this case, {\returntype} can usually be omitted -as it can be inferred from the type of the branches\footnote{Except if -the inductive type is empty in which case there is no equation that can be -used to infer the return type.}. - -In the {\em dependent} case, there are three subcases. In the first -subcase, the type in each branch may depend on the exact value being -matched in the branch. In this case, the whole pattern-matching itself -depends on the term being matched. This dependency of the term being -matched in the return type is expressed with an ``{\tt as {\ident}}'' -clause where {\ident} is dependent in the return type. -For instance, in the following example: -\begin{coq_example*} -Inductive bool : Type := true : bool | false : bool. -Inductive eq (A:Type) (x:A) : A -> Prop := eq_refl : eq A x x. -Inductive or (A:Prop) (B:Prop) : Prop := -| or_introl : A -> or A B -| or_intror : B -> or A B. -Definition bool_case (b:bool) : or (eq bool b true) (eq bool b false) -:= match b as x return or (eq bool x true) (eq bool x false) with - | true => or_introl (eq bool true true) (eq bool true false) - (eq_refl bool true) - | false => or_intror (eq bool false true) (eq bool false false) - (eq_refl bool false) - end. -\end{coq_example*} -the branches have respective types {\tt or (eq bool true true) (eq -bool true false)} and {\tt or (eq bool false true) (eq bool false -false)} while the whole pattern-matching expression has type {\tt or -(eq bool b true) (eq bool b false)}, the identifier {\tt x} being used -to represent the dependency. Remark that when the term being matched -is a variable, the {\tt as} clause can be omitted and the term being -matched can serve itself as binding name in the return type. For -instance, the following alternative definition is accepted and has the -same meaning as the previous one. -\begin{coq_eval} -Reset bool_case. -\end{coq_eval} -\begin{coq_example*} -Definition bool_case (b:bool) : or (eq bool b true) (eq bool b false) -:= match b return or (eq bool b true) (eq bool b false) with - | true => or_introl (eq bool true true) (eq bool true false) - (eq_refl bool true) - | false => or_intror (eq bool false true) (eq bool false false) - (eq_refl bool false) - end. -\end{coq_example*} - -The second subcase is only relevant for annotated inductive types such -as the equality predicate (see Section~\ref{Equality}), the order -predicate on natural numbers % (see Section~\ref{le}) % undefined reference -or the type of -lists of a given length (see Section~\ref{listn}). In this configuration, -the type of each branch can depend on the type dependencies specific -to the branch and the whole pattern-matching expression has a type -determined by the specific dependencies in the type of the term being -matched. This dependency of the return type in the annotations of the -inductive type is expressed using a - ``in~I~\_~$\ldots$~\_~\pattern$_1$~$\ldots$~\pattern$_n$'' clause, where -\begin{itemize} -\item $I$ is the inductive type of the term being matched; - -\item the {\_}'s are matching the parameters of the inductive type: -the return type is not dependent on them. - -\item the \pattern$_i$'s are matching the annotations of the inductive - type: the return type is dependent on them - -\item in the basic case which we describe below, each \pattern$_i$ is a - name \ident$_i$; see \ref{match-in-patterns} for the general case - -\end{itemize} - -For instance, in the following example: -\begin{coq_example*} -Definition eq_sym (A:Type) (x y:A) (H:eq A x y) : eq A y x := - match H in eq _ _ z return eq A z x with - | eq_refl _ _ => eq_refl A x - end. -\end{coq_example*} -the type of the branch has type {\tt eq~A~x~x} because the third -argument of {\tt eq} is {\tt x} in the type of the pattern {\tt -refl\_equal}. On the contrary, the type of the whole pattern-matching -expression has type {\tt eq~A~y~x} because the third argument of {\tt -eq} is {\tt y} in the type of {\tt H}. This dependency of the case -analysis in the third argument of {\tt eq} is expressed by the -identifier {\tt z} in the return type. - -Finally, the third subcase is a combination of the first and second -subcase. In particular, it only applies to pattern-matching on terms -in a type with annotations. For this third subcase, both -the clauses {\tt as} and {\tt in} are available. - -There are specific notations for case analysis on types with one or -two constructors: ``{\tt if {\ldots} then {\ldots} else {\ldots}}'' -and ``{\tt let (}\nelist{\ldots}{,}{\tt ) := } {\ldots} {\tt in} -{\ldots}'' (see Sections~\ref{if-then-else} and~\ref{Letin}). - -%\SeeAlso Section~\ref{Mult-match} for convenient extensions of pattern-matching. - -\subsection{Recursive functions -\label{fixpoints} -\index{fix@{fix \ident$_i$\{\dots\}}}} - -The expression ``{\tt fix} \ident$_1$ \binder$_1$ {\tt :} {\type$_1$} -\texttt{:=} \term$_1$ {\tt with} {\ldots} {\tt with} \ident$_n$ -\binder$_n$~{\tt :} {\type$_n$} \texttt{:=} \term$_n$ {\tt for} -{\ident$_i$}'' denotes the $i$\nth component of a block of functions -defined by mutual well-founded recursion. It is the local counterpart -of the {\tt Fixpoint} command. See Section~\ref{Fixpoint} for more -details. When $n=1$, the ``{\tt for}~{\ident$_i$}'' clause is omitted. - -The expression ``{\tt cofix} \ident$_1$~\binder$_1$ {\tt :} -{\type$_1$} {\tt with} {\ldots} {\tt with} \ident$_n$ \binder$_n$ {\tt -:} {\type$_n$}~{\tt for} {\ident$_i$}'' denotes the $i$\nth component of -a block of terms defined by a mutual guarded co-recursion. It is the -local counterpart of the {\tt CoFixpoint} command. See -Section~\ref{CoFixpoint} for more details. When $n=1$, the ``{\tt -for}~{\ident$_i$}'' clause is omitted. - -The association of a single fixpoint and a local -definition have a special syntax: ``{\tt let fix}~$f$~{\ldots}~{\tt - :=}~{\ldots}~{\tt in}~{\ldots}'' stands for ``{\tt let}~$f$~{\tt := - fix}~$f$~\ldots~{\tt :=}~{\ldots}~{\tt in}~{\ldots}''. The same - applies for co-fixpoints. - - -\section{The Vernacular -\label{Vernacular}} - -\begin{figure}[tbp] -\begin{centerframe} -\begin{tabular}{lcl} -{\sentence} & ::= & {\assumption} \\ - & $|$ & {\definition} \\ - & $|$ & {\inductive} \\ - & $|$ & {\fixpoint} \\ - & $|$ & {\assertion} {\proof} \\ -&&\\ -%% Assumptions -{\assumption} & ::= & {\assumptionkeyword} {\assums} {\tt .} \\ -&&\\ -{\assumptionkeyword} & $\!\!$ ::= & {\tt Axiom} $|$ {\tt Conjecture} \\ - & $|$ & {\tt Parameter} $|$ {\tt Parameters} \\ - & $|$ & {\tt Variable} $|$ {\tt Variables} \\ - & $|$ & {\tt Hypothesis} $|$ {\tt Hypotheses}\\ -&&\\ -{\assums} & ::= & \nelist{\ident}{} {\tt :} {\term} \\ - & $|$ & \nelist{{\tt (} \nelist{\ident}{} {\tt :} {\term} {\tt )}}{} \\ -&&\\ -%% Definitions -{\definition} & ::= & - \zeroone{\tt Local} {\tt Definition} {\ident} \zeroone{\binders} {\typecstr} {\tt :=} {\term} {\tt .} \\ - & $|$ & {\tt Let} {\ident} \zeroone{\binders} {\typecstr} {\tt :=} {\term} {\tt .} \\ -&&\\ -%% Inductives -{\inductive} & ::= & - {\tt Inductive} \nelist{\inductivebody}{with} {\tt .} \\ - & $|$ & {\tt CoInductive} \nelist{\inductivebody}{with} {\tt .} \\ - & & \\ -{\inductivebody} & ::= & - {\ident} \zeroone{\binders} {\typecstr} {\tt :=} \\ - && ~~\zeroone{\zeroone{\tt |} \nelist{$\!${\ident}$\!$ \zeroone{\binders} {\typecstr}}{|}} \\ - & & \\ %% TODO: where ... -%% Fixpoints -{\fixpoint} & ::= & {\tt Fixpoint} \nelist{\fixpointbody}{with} {\tt .} \\ - & $|$ & {\tt CoFixpoint} \nelist{\cofixpointbody}{with} {\tt .} \\ -&&\\ -%% Lemmas & proofs -{\assertion} & ::= & - {\statkwd} {\ident} \zeroone{\binders} {\tt :} {\term} {\tt .} \\ -&&\\ - {\statkwd} & ::= & {\tt Theorem} $|$ {\tt Lemma} \\ - & $|$ & {\tt Remark} $|$ {\tt Fact}\\ - & $|$ & {\tt Corollary} $|$ {\tt Proposition} \\ - & $|$ & {\tt Definition} $|$ {\tt Example} \\\\ -&&\\ -{\proof} & ::= & {\tt Proof} {\tt .} {\dots} {\tt Qed} {\tt .}\\ - & $|$ & {\tt Proof} {\tt .} {\dots} {\tt Defined} {\tt .}\\ - & $|$ & {\tt Proof} {\tt .} {\dots} {\tt Admitted} {\tt .}\\ -\end{tabular} -\end{centerframe} -\caption{Syntax of sentences} -\label{sentences-syntax} -\end{figure} - -Figure \ref{sentences-syntax} describes {\em The Vernacular} which is the -language of commands of \gallina. A sentence of the vernacular -language, like in many natural languages, begins with a capital letter -and ends with a dot. - -The different kinds of command are described hereafter. They all suppose -that the terms occurring in the sentences are well-typed. - -%% -%% Axioms and Parameters -%% -\subsection{Assumptions -\index{Declarations} -\label{Declarations}} - -Assumptions extend the environment\index{Environment} with axioms, -parameters, hypotheses or variables. An assumption binds an {\ident} -to a {\type}. It is accepted by {\Coq} if and only if this {\type} is -a correct type in the environment preexisting the declaration and if -{\ident} was not previously defined in the same module. This {\type} -is considered to be the type (or specification, or statement) assumed -by {\ident} and we say that {\ident} has type {\type}. - -\subsubsection{{\tt Axiom {\ident} :{\term} .} -\comindex{Axiom} -\label{Axiom}} - -This command links {\term} to the name {\ident} as its specification -in the global context. The fact asserted by {\term} is thus assumed as -a postulate. - -\begin{ErrMsgs} -\item \errindex{{\ident} already exists} -\end{ErrMsgs} - -\begin{Variants} -\item \comindex{Parameter}\comindex{Parameters} - {\tt Parameter {\ident} :{\term}.} \\ - Is equivalent to {\tt Axiom {\ident} : {\term}} - -\item {\tt Parameter {\ident$_1$} {\ldots} {\ident$_n$} {\tt :}{\term}.}\\ - Adds $n$ parameters with specification {\term} - -\item - {\tt Parameter\,% -(\,{\ident$_{1,1}$} {\ldots} {\ident$_{1,k_1}$}\,{\tt :}\,{\term$_1$} {\tt )}\;% -\ldots\;{\tt (}\,{\ident$_{n,1}$}{\ldots}{\ident$_{n,k_n}$}\,{\tt :}\,% -{\term$_n$} {\tt )}.}\\ - Adds $n$ blocks of parameters with different specifications. - -\item {\tt Local Axiom {\ident} : {\term}.}\\ -\comindex{Local Axiom} - Such axioms are never made accessible through their unqualified name by - {\tt Import} and its variants (see \ref{Import}). You have to explicitly - give their fully qualified name to refer to them. - -\item \comindex{Conjecture} - {\tt Conjecture {\ident} :{\term}.}\\ - Is equivalent to {\tt Axiom {\ident} : {\term}}. -\end{Variants} - -\noindent {\bf Remark: } It is possible to replace {\tt Parameter} by -{\tt Parameters}. - - -\subsubsection{{\tt Variable {\ident} :{\term}}. -\comindex{Variable} -\comindex{Variables} -\label{Variable}} - -This command links {\term} to the name {\ident} in the context of the -current section (see Section~\ref{Section} for a description of the section -mechanism). When the current section is closed, name {\ident} will be -unknown and every object using this variable will be explicitly -parametrized (the variable is {\em discharged}). Using the {\tt -Variable} command out of any section is equivalent to using {\tt -Local Parameter}. - -\begin{ErrMsgs} -\item \errindex{{\ident} already exists} -\end{ErrMsgs} - -\begin{Variants} -\item {\tt Variable {\ident$_1$} {\ldots} {\ident$_n$} {\tt :}{\term}.}\\ - Links {\term} to names {\ident$_1$} {\ldots} {\ident$_n$}. -\item - {\tt Variable\,% -(\,{\ident$_{1,1}$} {\ldots} {\ident$_{1,k_1}$}\,{\tt :}\,{\term$_1$} {\tt )}\;% -\ldots\;{\tt (}\,{\ident$_{n,1}$} {\ldots}{\ident$_{n,k_n}$}\,{\tt :}\,% -{\term$_n$} {\tt )}.}\\ - Adds $n$ blocks of variables with different specifications. -\item \comindex{Hypothesis} - \comindex{Hypotheses} - {\tt Hypothesis {\ident} {\tt :}{\term}.} \\ - \texttt{Hypothesis} is a synonymous of \texttt{Variable} -\end{Variants} - -\noindent {\bf Remark: } It is possible to replace {\tt Variable} by -{\tt Variables} and {\tt Hypothesis} by {\tt Hypotheses}. - -It is advised to use the keywords \verb:Axiom: and \verb:Hypothesis: -for logical postulates (i.e. when the assertion {\term} is of sort -\verb:Prop:), and to use the keywords \verb:Parameter: and -\verb:Variable: in other cases (corresponding to the declaration of an -abstract mathematical entity). - -%% -%% Definitions -%% -\subsection{Definitions -\index{Definitions} -\label{Basic-definitions}} - -Definitions extend the environment\index{Environment} with -associations of names to terms. A definition can be seen as a way to -give a meaning to a name or as a way to abbreviate a term. In any -case, the name can later be replaced at any time by its definition. - -The operation of unfolding a name into its definition is called -$\delta$-conversion\index{delta-reduction@$\delta$-reduction} (see -Section~\ref{delta}). A definition is accepted by the system if and -only if the defined term is well-typed in the current context of the -definition and if the name is not already used. The name defined by -the definition is called a {\em constant}\index{Constant} and the term -it refers to is its {\em body}. A definition has a type which is the -type of its body. - -A formal presentation of constants and environments is given in -Section~\ref{Typed-terms}. - -\subsubsection{\tt Definition {\ident} := {\term}. -\label{Definition} -\comindex{Definition}} - -This command binds {\term} to the name {\ident} in the -environment, provided that {\term} is well-typed. - -\begin{ErrMsgs} -\item \errindex{{\ident} already exists} -\end{ErrMsgs} - -\begin{Variants} -\item {\tt Definition} {\ident} {\tt :} {\term$_1$} {\tt :=} {\term$_2$}{\tt .}\\ - It checks that the type of {\term$_2$} is definitionally equal to - {\term$_1$}, and registers {\ident} as being of type {\term$_1$}, - and bound to value {\term$_2$}. -\item {\tt Definition} {\ident} {\binder$_1$} {\ldots} {\binder$_n$} - {\tt :} \term$_1$ {\tt :=} {\term$_2$}{\tt .}\\ - This is equivalent to \\ - {\tt Definition} {\ident} {\tt : forall}% - {\binder$_1$} {\ldots} {\binder$_n$}{\tt ,}\,\term$_1$\,{\tt :=}\,% - {\tt fun}\,{\binder$_1$} {\ldots} {\binder$_n$}\,{\tt =>}\,{\term$_2$}\,% - {\tt .} - -\item {\tt Local Definition {\ident} := {\term}.}\\ -\comindex{Local Definition} - Such definitions are never made accessible through their unqualified name by - {\tt Import} and its variants (see \ref{Import}). You have to explicitly - give their fully qualified name to refer to them. -\item {\tt Example {\ident} := {\term}.}\\ -{\tt Example} {\ident} {\tt :} {\term$_1$} {\tt :=} {\term$_2$}{\tt .}\\ -{\tt Example} {\ident} {\binder$_1$} {\ldots} {\binder$_n$} - {\tt :} {\term$_1$} {\tt :=} {\term$_2$}{\tt .}\\ -\comindex{Example} -These are synonyms of the {\tt Definition} forms. -\end{Variants} - -\begin{ErrMsgs} -\item \errindex{The term {\term} has type {\type} while it is expected to have type {\type}} -\end{ErrMsgs} - -\SeeAlso Sections \ref{Opaque}, \ref{Transparent}, \ref{unfold}. - -\subsubsection{\tt Let {\ident} := {\term}. -\comindex{Let}} - -This command binds the value {\term} to the name {\ident} in the -environment of the current section. The name {\ident} disappears -when the current section is eventually closed, and, all -persistent objects (such as theorems) defined within the -section and depending on {\ident} are prefixed by the let-in definition -{\tt let {\ident} := {\term} in}. Using the {\tt -Let} command out of any section is equivalent to using {\tt -Local Definition}. - -\begin{ErrMsgs} -\item \errindex{{\ident} already exists} -\end{ErrMsgs} - -\begin{Variants} -\item {\tt Let {\ident} : {\term$_1$} := {\term$_2$}.} -\item {\tt Let Fixpoint {\ident} \nelist{\fixpointbody}{with} {\tt .}.} -\item {\tt Let CoFixpoint {\ident} \nelist{\cofixpointbody}{with} {\tt .}.} -\end{Variants} - -\SeeAlso Sections \ref{Section} (section mechanism), \ref{Opaque}, -\ref{Transparent} (opaque/transparent constants), \ref{unfold} (tactic - {\tt unfold}). - -%% -%% Inductive Types -%% -\subsection{Inductive definitions -\index{Inductive definitions} -\label{gal-Inductive-Definitions} -\comindex{Inductive} -\label{Inductive} -\comindex{Variant} -\label{Variant}} - -We gradually explain simple inductive types, simple -annotated inductive types, simple parametric inductive types, -mutually inductive types. We explain also co-inductive types. - -\subsubsection{Simple inductive types} - -The definition of a simple inductive type has the following form: - -\medskip -\begin{tabular}{l} -{\tt Inductive} {\ident} {\tt :} {\sort} {\tt :=} \\ -\begin{tabular}{clcl} - & {\ident$_1$} & {\tt :} & {\type$_1$} \\ - {\tt |} & {\ldots} && \\ - {\tt |} & {\ident$_n$} & {\tt :} & {\type$_n$} \\ -\end{tabular} -\end{tabular} -\medskip - -The name {\ident} is the name of the inductively defined type and -{\sort} is the universes where it lives. -The names {\ident$_1$}, {\ldots}, {\ident$_n$} -are the names of its constructors and {\type$_1$}, {\ldots}, -{\type$_n$} their respective types. The types of the constructors have -to satisfy a {\em positivity condition} (see Section~\ref{Positivity}) -for {\ident}. This condition ensures the soundness of the inductive -definition. If this is the case, the names {\ident}, -{\ident$_1$}, {\ldots}, {\ident$_n$} are added to the environment with -their respective types. Accordingly to the universe where -the inductive type lives ({\it e.g.} its type {\sort}), {\Coq} provides a -number of destructors for {\ident}. Destructors are named -{\ident}{\tt\_ind}, {\ident}{\tt \_rec} or {\ident}{\tt \_rect} which -respectively correspond to elimination principles on {\tt Prop}, {\tt -Set} and {\tt Type}. The type of the destructors expresses structural -induction/recursion principles over objects of {\ident}. We give below -two examples of the use of the {\tt Inductive} definitions. - -The set of natural numbers is defined as: -\begin{coq_example} -Inductive nat : Set := - | O : nat - | S : nat -> nat. -\end{coq_example} - -The type {\tt nat} is defined as the least \verb:Set: containing {\tt - O} and closed by the {\tt S} constructor. The names {\tt nat}, -{\tt O} and {\tt S} are added to the environment. - -Now let us have a look at the elimination principles. They are three -of them: -{\tt nat\_ind}, {\tt nat\_rec} and {\tt nat\_rect}. The type of {\tt - nat\_ind} is: -\begin{coq_example} -Check nat_ind. -\end{coq_example} - -This is the well known structural induction principle over natural -numbers, i.e. the second-order form of Peano's induction principle. -It allows proving some universal property of natural numbers ({\tt -forall n:nat, P n}) by induction on {\tt n}. - -The types of {\tt nat\_rec} and {\tt nat\_rect} are similar, except -that they pertain to {\tt (P:nat->Set)} and {\tt (P:nat->Type)} -respectively . They correspond to primitive induction principles -(allowing dependent types) respectively over sorts \verb:Set: and -\verb:Type:. The constant {\ident}{\tt \_ind} is always provided, -whereas {\ident}{\tt \_rec} and {\ident}{\tt \_rect} can be impossible -to derive (for example, when {\ident} is a proposition). - -\begin{coq_eval} -Reset Initial. -\end{coq_eval} -\begin{Variants} -\item -\begin{coq_example*} -Inductive nat : Set := O | S (_:nat). -\end{coq_example*} -In the case where inductive types have no annotations (next section -gives an example of such annotations), -%the positivity condition implies that -a constructor can be defined by only giving the type of -its arguments. -\end{Variants} - -\subsubsection{Simple annotated inductive types} - -In an annotated inductive types, the universe where the inductive -type is defined is no longer a simple sort, but what is called an -arity, which is a type whose conclusion is a sort. - -As an example of annotated inductive types, let us define the -$even$ predicate: - -\begin{coq_example} -Inductive even : nat -> Prop := - | even_0 : even O - | even_SS : forall n:nat, even n -> even (S (S n)). -\end{coq_example} - -The type {\tt nat->Prop} means that {\tt even} is a unary predicate -(inductively defined) over natural numbers. The type of its two -constructors are the defining clauses of the predicate {\tt even}. The -type of {\tt even\_ind} is: - -\begin{coq_example} -Check even_ind. -\end{coq_example} - -From a mathematical point of view it asserts that the natural numbers -satisfying the predicate {\tt even} are exactly in the smallest set of -naturals satisfying the clauses {\tt even\_0} or {\tt even\_SS}. This -is why, when we want to prove any predicate {\tt P} over elements of -{\tt even}, it is enough to prove it for {\tt O} and to prove that if -any natural number {\tt n} satisfies {\tt P} its double successor {\tt - (S (S n))} satisfies also {\tt P}. This is indeed analogous to the -structural induction principle we got for {\tt nat}. - -\begin{ErrMsgs} -\item \errindex{Non strictly positive occurrence of {\ident} in {\type}} -\item \errindex{The conclusion of {\type} is not valid; it must be -built from {\ident}} -\end{ErrMsgs} - -\subsubsection{Parametrized inductive types} -In the previous example, each constructor introduces a -different instance of the predicate {\tt even}. In some cases, -all the constructors introduces the same generic instance of the -inductive definition, in which case, instead of an annotation, we use -a context of parameters which are binders shared by all the -constructors of the definition. - -% Inductive types may be parameterized. Parameters differ from inductive -% type annotations in the fact that recursive invokations of inductive -% types must always be done with the same values of parameters as its -% specification. - -The general scheme is: -\begin{center} -{\tt Inductive} {\ident} {\binder$_1$}\ldots{\binder$_k$} : {\term} := - {\ident$_1$}: {\term$_1$} | {\ldots} | {\ident$_n$}: \term$_n$ -{\tt .} -\end{center} -Parameters differ from inductive type annotations in the fact that the -conclusion of each type of constructor {\term$_i$} invoke the inductive -type with the same values of parameters as its specification. - - - -A typical example is the definition of polymorphic lists: -\begin{coq_example*} -Inductive list (A:Set) : Set := - | nil : list A - | cons : A -> list A -> list A. -\end{coq_example*} - -Note that in the type of {\tt nil} and {\tt cons}, we write {\tt - (list A)} and not just {\tt list}.\\ The constructors {\tt nil} and -{\tt cons} will have respectively types: - -\begin{coq_example} -Check nil. -Check cons. -\end{coq_example} - -Types of destructors are also quantified with {\tt (A:Set)}. - -\begin{coq_eval} -Reset Initial. -\end{coq_eval} -\begin{Variants} -\item -\begin{coq_example*} -Inductive list (A:Set) : Set := nil | cons (_:A) (_:list A). -\end{coq_example*} -This is an alternative definition of lists where we specify the -arguments of the constructors rather than their full type. -\item -\begin{coq_example*} -Variant sum (A B:Set) : Set := left : A -> sum A B | right : B -> sum A B. -\end{coq_example*} -The {\tt Variant} keyword is identical to the {\tt Inductive} keyword, -except that it disallows recursive definition of types (in particular -lists cannot be defined with the {\tt Variant} keyword). No induction -scheme is generated for this variant, unless the option -{\tt Nonrecursive Elimination Schemes} is set -(see~\ref{set-nonrecursive-elimination-schemes}). -\end{Variants} - -\begin{ErrMsgs} -\item \errindex{The {\num}th argument of {\ident} must be {\ident'} in -{\type}} -\end{ErrMsgs} - -\paragraph{New from \Coq{} V8.1} The condition on parameters for -inductive definitions has been relaxed since \Coq{} V8.1. It is now -possible in the type of a constructor, to invoke recursively the -inductive definition on an argument which is not the parameter itself. - -One can define~: -\begin{coq_example} -Inductive list2 (A:Set) : Set := - | nil2 : list2 A - | cons2 : A -> list2 (A*A) -> list2 A. -\end{coq_example} -\begin{coq_eval} -Reset list2. -\end{coq_eval} -that can also be written by specifying only the type of the arguments: -\begin{coq_example*} -Inductive list2 (A:Set) : Set := nil2 | cons2 (_:A) (_:list2 (A*A)). -\end{coq_example*} -But the following definition will give an error: -\begin{coq_example} -Fail Inductive listw (A:Set) : Set := - | nilw : listw (A*A) - | consw : A -> listw (A*A) -> listw (A*A). -\end{coq_example} -Because the conclusion of the type of constructors should be {\tt - listw A} in both cases. - -A parametrized inductive definition can be defined using -annotations instead of parameters but it will sometimes give a -different (bigger) sort for the inductive definition and will produce -a less convenient rule for case elimination. - -\SeeAlso Sections~\ref{Cic-inductive-definitions} and~\ref{Tac-induction}. - - -\subsubsection{Mutually defined inductive types -\comindex{Inductive} -\label{Mutual-Inductive}} - -The definition of a block of mutually inductive types has the form: - -\medskip -{\tt -\begin{tabular}{l} -Inductive {\ident$_1$} : {\type$_1$} := \\ -\begin{tabular}{clcl} - & {\ident$_1^1$} &:& {\type$_1^1$} \\ - | & {\ldots} && \\ - | & {\ident$_{n_1}^1$} &:& {\type$_{n_1}^1$} -\end{tabular} \\ -with\\ -~{\ldots} \\ -with {\ident$_m$} : {\type$_m$} := \\ -\begin{tabular}{clcl} - & {\ident$_1^m$} &:& {\type$_1^m$} \\ - | & {\ldots} \\ - | & {\ident$_{n_m}^m$} &:& {\type$_{n_m}^m$}. -\end{tabular} -\end{tabular} -} -\medskip - -\noindent It has the same semantics as the above {\tt Inductive} -definition for each \ident$_1$, {\ldots}, \ident$_m$. All names -\ident$_1$, {\ldots}, \ident$_m$ and \ident$_1^1$, \dots, -\ident$_{n_m}^m$ are simultaneously added to the environment. Then -well-typing of constructors can be checked. Each one of the -\ident$_1$, {\ldots}, \ident$_m$ can be used on its own. - -It is also possible to parametrize these inductive definitions. -However, parameters correspond to a local -context in which the whole set of inductive declarations is done. For -this reason, the parameters must be strictly the same for each -inductive types The extended syntax is: - -\medskip -\begin{tabular}{l} -{\tt Inductive} {\ident$_1$} {\params} {\tt :} {\type$_1$} {\tt :=} \\ -\begin{tabular}{clcl} - & {\ident$_1^1$} &{\tt :}& {\type$_1^1$} \\ - {\tt |} & {\ldots} && \\ - {\tt |} & {\ident$_{n_1}^1$} &{\tt :}& {\type$_{n_1}^1$} -\end{tabular} \\ -{\tt with}\\ -~{\ldots} \\ -{\tt with} {\ident$_m$} {\params} {\tt :} {\type$_m$} {\tt :=} \\ -\begin{tabular}{clcl} - & {\ident$_1^m$} &{\tt :}& {\type$_1^m$} \\ - {\tt |} & {\ldots} \\ - {\tt |} & {\ident$_{n_m}^m$} &{\tt :}& {\type$_{n_m}^m$}. -\end{tabular} -\end{tabular} -\medskip - -\Example -The typical example of a mutual inductive data type is the one for -trees and forests. We assume given two types $A$ and $B$ as variables. -It can be declared the following way. - -\begin{coq_eval} -Reset Initial. -\end{coq_eval} -\begin{coq_example*} -Variables A B : Set. -Inductive tree : Set := - node : A -> forest -> tree -with forest : Set := - | leaf : B -> forest - | cons : tree -> forest -> forest. -\end{coq_example*} - -This declaration generates automatically six induction -principles. They are respectively -called {\tt tree\_rec}, {\tt tree\_ind}, {\tt - tree\_rect}, {\tt forest\_rec}, {\tt forest\_ind}, {\tt - forest\_rect}. These ones are not the most general ones but are -just the induction principles corresponding to each inductive part -seen as a single inductive definition. - -To illustrate this point on our example, we give the types of {\tt - tree\_rec} and {\tt forest\_rec}. - -\begin{coq_example} -Check tree_rec. -Check forest_rec. -\end{coq_example} - -Assume we want to parametrize our mutual inductive definitions with -the two type variables $A$ and $B$, the declaration should be done the -following way: - -\begin{coq_eval} -Reset tree. -\end{coq_eval} -\begin{coq_example*} -Inductive tree (A B:Set) : Set := - node : A -> forest A B -> tree A B -with forest (A B:Set) : Set := - | leaf : B -> forest A B - | cons : tree A B -> forest A B -> forest A B. -\end{coq_example*} - -Assume we define an inductive definition inside a section. When the -section is closed, the variables declared in the section and occurring -free in the declaration are added as parameters to the inductive -definition. - -\SeeAlso Section~\ref{Section}. - -\subsubsection{Co-inductive types -\label{CoInductiveTypes} -\comindex{CoInductive}} - -The objects of an inductive type are well-founded with respect to the -constructors of the type. In other words, such objects contain only a -{\it finite} number of constructors. Co-inductive types arise from -relaxing this condition, and admitting types whose objects contain an -infinity of constructors. Infinite objects are introduced by a -non-ending (but effective) process of construction, defined in terms -of the constructors of the type. - -An example of a co-inductive type is the type of infinite sequences of -natural numbers, usually called streams. It can be introduced in \Coq\ -using the \texttt{CoInductive} command: -\begin{coq_example} -CoInductive Stream : Set := - Seq : nat -> Stream -> Stream. -\end{coq_example} - -The syntax of this command is the same as the command \texttt{Inductive} -(see Section~\ref{gal-Inductive-Definitions}). Notice that no -principle of induction is derived from the definition of a -co-inductive type, since such principles only make sense for inductive -ones. For co-inductive ones, the only elimination principle is case -analysis. For example, the usual destructors on streams -\texttt{hd:Stream->nat} and \texttt{tl:Str->Str} can be defined as -follows: -\begin{coq_example} -Definition hd (x:Stream) := let (a,s) := x in a. -Definition tl (x:Stream) := let (a,s) := x in s. -\end{coq_example} - -Definition of co-inductive predicates and blocks of mutually -co-inductive definitions are also allowed. An example of a -co-inductive predicate is the extensional equality on streams: - -\begin{coq_example} -CoInductive EqSt : Stream -> Stream -> Prop := - eqst : - forall s1 s2:Stream, - hd s1 = hd s2 -> EqSt (tl s1) (tl s2) -> EqSt s1 s2. -\end{coq_example} - -In order to prove the extensionally equality of two streams $s_1$ and -$s_2$ we have to construct an infinite proof of equality, that is, -an infinite object of type $(\texttt{EqSt}\;s_1\;s_2)$. We will see -how to introduce infinite objects in Section~\ref{CoFixpoint}. - -%% -%% (Co-)Fixpoints -%% -\subsection{Definition of recursive functions} - -\subsubsection{Definition of functions by recursion over inductive objects} - -This section describes the primitive form of definition by recursion -over inductive objects. See Section~\ref{Function} for more advanced -constructions. The command: -\begin{center} - \texttt{Fixpoint {\ident} {\params} {\tt \{struct} - \ident$_0$ {\tt \}} : type$_0$ := \term$_0$ - \comindex{Fixpoint}\label{Fixpoint}} -\end{center} -allows defining functions by pattern-matching over inductive objects -using a fixed point construction. -The meaning of this declaration is to define {\it ident} a recursive -function with arguments specified by the binders in {\params} such -that {\it ident} applied to arguments corresponding to these binders -has type \type$_0$, and is equivalent to the expression \term$_0$. The -type of the {\ident} is consequently {\tt forall {\params} {\tt,} - \type$_0$} and the value is equivalent to {\tt fun {\params} {\tt - =>} \term$_0$}. - -To be accepted, a {\tt Fixpoint} definition has to satisfy some -syntactical constraints on a special argument called the decreasing -argument. They are needed to ensure that the {\tt Fixpoint} definition -always terminates. The point of the {\tt \{struct \ident {\tt \}}} -annotation is to let the user tell the system which argument decreases -along the recursive calls. For instance, one can define the addition -function as : - -\begin{coq_example} -Fixpoint add (n m:nat) {struct n} : nat := - match n with - | O => m - | S p => S (add p m) - end. -\end{coq_example} - -The {\tt \{struct \ident {\tt \}}} annotation may be left implicit, in -this case the system try successively arguments from left to right -until it finds one that satisfies the decreasing condition. Note that -some fixpoints may have several arguments that fit as decreasing -arguments, and this choice influences the reduction of the -fixpoint. Hence an explicit annotation must be used if the leftmost -decreasing argument is not the desired one. Writing explicit -annotations can also speed up type-checking of large mutual fixpoints. - -The {\tt match} operator matches a value (here \verb:n:) with the -various constructors of its (inductive) type. The remaining arguments -give the respective values to be returned, as functions of the -parameters of the corresponding constructor. Thus here when \verb:n: -equals \verb:O: we return \verb:m:, and when \verb:n: equals -\verb:(S p): we return \verb:(S (add p m)):. - -The {\tt match} operator is formally described -in detail in Section~\ref{Caseexpr}. The system recognizes that in -the inductive call {\tt (add p m)} the first argument actually -decreases because it is a {\em pattern variable} coming from {\tt match - n with}. - -\Example The following definition is not correct and generates an -error message: - -\begin{coq_eval} -Set Printing Depth 50. -\end{coq_eval} -% (********** The following is not correct and should produce **********) -% (********* Error: Recursive call to wrongplus ... **********) -\begin{coq_example} -Fail Fixpoint wrongplus (n m:nat) {struct n} : nat := - match m with - | O => n - | S p => S (wrongplus n p) - end. -\end{coq_example} - -because the declared decreasing argument {\tt n} actually does not -decrease in the recursive call. The function computing the addition -over the second argument should rather be written: - -\begin{coq_example*} -Fixpoint plus (n m:nat) {struct m} : nat := - match m with - | O => n - | S p => S (plus n p) - end. -\end{coq_example*} - -The ordinary match operation on natural numbers can be mimicked in the -following way. -\begin{coq_example*} -Fixpoint nat_match - (C:Set) (f0:C) (fS:nat -> C -> C) (n:nat) {struct n} : C := - match n with - | O => f0 - | S p => fS p (nat_match C f0 fS p) - end. -\end{coq_example*} -The recursive call may not only be on direct subterms of the recursive -variable {\tt n} but also on a deeper subterm and we can directly -write the function {\tt mod2} which gives the remainder modulo 2 of a -natural number. -\begin{coq_example*} -Fixpoint mod2 (n:nat) : nat := - match n with - | O => O - | S p => match p with - | O => S O - | S q => mod2 q - end - end. -\end{coq_example*} -In order to keep the strong normalization property, the fixed point -reduction will only be performed when the argument in position of the -decreasing argument (which type should be in an inductive definition) -starts with a constructor. - -The {\tt Fixpoint} construction enjoys also the {\tt with} extension -to define functions over mutually defined inductive types or more -generally any mutually recursive definitions. - -\begin{Variants} -\item {\tt Fixpoint} {\ident$_1$} {\params$_1$} {\tt :} {\type$_1$} {\tt :=} {\term$_1$}\\ - {\tt with} {\ldots} \\ - {\tt with} {\ident$_m$} {\params$_m$} {\tt :} {\type$_m$} {\tt :=} {\term$_m$}\\ - Allows to define simultaneously {\ident$_1$}, {\ldots}, - {\ident$_m$}. -\end{Variants} - -\Example -The size of trees and forests can be defined the following way: -\begin{coq_eval} -Reset Initial. -Variables A B : Set. -Inductive tree : Set := - node : A -> forest -> tree -with forest : Set := - | leaf : B -> forest - | cons : tree -> forest -> forest. -\end{coq_eval} -\begin{coq_example*} -Fixpoint tree_size (t:tree) : nat := - match t with - | node a f => S (forest_size f) - end - with forest_size (f:forest) : nat := - match f with - | leaf b => 1 - | cons t f' => (tree_size t + forest_size f') - end. -\end{coq_example*} -A generic command {\tt Scheme} is useful to build automatically various -mutual induction principles. It is described in Section~\ref{Scheme}. - -\subsubsection{Definitions of recursive objects in co-inductive types} - -The command: -\begin{center} - \texttt{CoFixpoint {\ident} : \type$_0$ := \term$_0$} - \comindex{CoFixpoint}\label{CoFixpoint} -\end{center} -introduces a method for constructing an infinite object of a -coinduc\-tive type. For example, the stream containing all natural -numbers can be introduced applying the following method to the number -\texttt{O} (see Section~\ref{CoInductiveTypes} for the definition of -{\tt Stream}, {\tt hd} and {\tt tl}): -\begin{coq_eval} -Reset Initial. -CoInductive Stream : Set := - Seq : nat -> Stream -> Stream. -Definition hd (x:Stream) := match x with - | Seq a s => a - end. -Definition tl (x:Stream) := match x with - | Seq a s => s - end. -\end{coq_eval} -\begin{coq_example} -CoFixpoint from (n:nat) : Stream := Seq n (from (S n)). -\end{coq_example} - -Oppositely to recursive ones, there is no decreasing argument in a -co-recursive definition. To be admissible, a method of construction -must provide at least one extra constructor of the infinite object for -each iteration. A syntactical guard condition is imposed on -co-recursive definitions in order to ensure this: each recursive call -in the definition must be protected by at least one constructor, and -only by constructors. That is the case in the former definition, where -the single recursive call of \texttt{from} is guarded by an -application of \texttt{Seq}. On the contrary, the following recursive -function does not satisfy the guard condition: - -\begin{coq_eval} -Set Printing Depth 50. -\end{coq_eval} -% (********** The following is not correct and should produce **********) -% (***************** Error: Unguarded recursive call *******************) -\begin{coq_example} -Fail CoFixpoint filter (p:nat -> bool) (s:Stream) : Stream := - if p (hd s) then Seq (hd s) (filter p (tl s)) else filter p (tl s). -\end{coq_example} - -The elimination of co-recursive definition is done lazily, i.e. the -definition is expanded only when it occurs at the head of an -application which is the argument of a case analysis expression. In -any other context, it is considered as a canonical expression which is -completely evaluated. We can test this using the command -\texttt{Eval}, which computes the normal forms of a term: - -\begin{coq_example} -Eval compute in (from 0). -Eval compute in (hd (from 0)). -Eval compute in (tl (from 0)). -\end{coq_example} - -\begin{Variants} -\item{\tt CoFixpoint {\ident$_1$} {\params} :{\type$_1$} := - {\term$_1$}}\\ As for most constructions, arguments of co-fixpoints - expressions can be introduced before the {\tt :=} sign. -\item{\tt CoFixpoint} {\ident$_1$} {\tt :} {\type$_1$} {\tt :=} {\term$_1$}\\ - {\tt with}\\ - \mbox{}\hspace{0.1cm} {\ldots} \\ - {\tt with} {\ident$_m$} {\tt :} {\type$_m$} {\tt :=} {\term$_m$}\\ -As in the \texttt{Fixpoint} command (see Section~\ref{Fixpoint}), it -is possible to introduce a block of mutually dependent methods. -\end{Variants} - -%% -%% Theorems & Lemmas -%% -\subsection{Assertions and proofs} -\label{Assertions} - -An assertion states a proposition (or a type) of which the proof (or -an inhabitant of the type) is interactively built using tactics. The -interactive proof mode is described in -Chapter~\ref{Proof-handling} and the tactics in Chapter~\ref{Tactics}. -The basic assertion command is: - -\subsubsection{\tt Theorem {\ident} \zeroone{\binders} : {\type}. -\comindex{Theorem}} - -After the statement is asserted, {\Coq} needs a proof. Once a proof of -{\type} under the assumptions represented by {\binders} is given and -validated, the proof is generalized into a proof of {\tt forall - \zeroone{\binders}, {\type}} and the theorem is bound to the name -{\ident} in the environment. - -\begin{ErrMsgs} - -\item \errindex{The term {\form} has type {\ldots} which should be Set, - Prop or Type} - -\item \errindexbis{{\ident} already exists}{already exists} - - The name you provided is already defined. You have then to choose - another name. - -\end{ErrMsgs} - -\begin{Variants} -\item {\tt Lemma {\ident} \zeroone{\binders} : {\type}.}\comindex{Lemma}\\ - {\tt Remark {\ident} \zeroone{\binders} : {\type}.}\comindex{Remark}\\ - {\tt Fact {\ident} \zeroone{\binders} : {\type}.}\comindex{Fact}\\ - {\tt Corollary {\ident} \zeroone{\binders} : {\type}.}\comindex{Corollary}\\ - {\tt Proposition {\ident} \zeroone{\binders} : {\type}.}\comindex{Proposition} - -These commands are synonyms of \texttt{Theorem {\ident} \zeroone{\binders} : {\type}}. - -\item {\tt Theorem \nelist{{\ident} \zeroone{\binders}: {\type}}{with}.} - -This command is useful for theorems that are proved by simultaneous -induction over a mutually inductive assumption, or that assert mutually -dependent statements in some mutual co-inductive type. It is equivalent -to {\tt Fixpoint} or {\tt CoFixpoint} -(see Section~\ref{CoFixpoint}) but using tactics to build the proof of -the statements (or the body of the specification, depending on the -point of view). The inductive or co-inductive types on which the -induction or coinduction has to be done is assumed to be non ambiguous -and is guessed by the system. - -Like in a {\tt Fixpoint} or {\tt CoFixpoint} definition, the induction -hypotheses have to be used on {\em structurally smaller} arguments -(for a {\tt Fixpoint}) or be {\em guarded by a constructor} (for a {\tt - CoFixpoint}). The verification that recursive proof arguments are -correct is done only at the time of registering the lemma in the -environment. To know if the use of induction hypotheses is correct at -some time of the interactive development of a proof, use the command -{\tt Guarded} (see Section~\ref{Guarded}). - -The command can be used also with {\tt Lemma}, -{\tt Remark}, etc. instead of {\tt Theorem}. - -\item {\tt Definition {\ident} \zeroone{\binders} : {\type}.} - -This allows defining a term of type {\type} using the proof editing mode. It -behaves as {\tt Theorem} but is intended to be used in conjunction with - {\tt Defined} (see \ref{Defined}) in order to define a - constant of which the computational behavior is relevant. - -The command can be used also with {\tt Example} instead -of {\tt Definition}. - -\SeeAlso Sections~\ref{Opaque} and~\ref{Transparent} ({\tt Opaque} -and {\tt Transparent}) and~\ref{unfold} (tactic {\tt unfold}). - -\item {\tt Let {\ident} \zeroone{\binders} : {\type}.} - -Like {\tt Definition {\ident} \zeroone{\binders} : {\type}.} except -that the definition is turned into a let-in definition generalized over -the declarations depending on it after closing the current section. - -\item {\tt Fixpoint \nelist{{\ident} {\binders} \zeroone{\annotation} {\typecstr} \zeroone{{\tt :=} {\term}}}{with}.} -\comindex{Fixpoint} - -This generalizes the syntax of {\tt Fixpoint} so that one or more -bodies can be defined interactively using the proof editing mode (when -a body is omitted, its type is mandatory in the syntax). When the -block of proofs is completed, it is intended to be ended by {\tt - Defined}. - -\item {\tt CoFixpoint \nelist{{\ident} \zeroone{\binders} {\typecstr} \zeroone{{\tt :=} {\term}}}{with}.} -\comindex{CoFixpoint} - -This generalizes the syntax of {\tt CoFixpoint} so that one or more bodies -can be defined interactively using the proof editing mode. - -\end{Variants} - -\subsubsection{{\tt Proof.} {\dots} {\tt Qed.} -\comindex{Proof} -\comindex{Qed}} - -A proof starts by the keyword {\tt Proof}. Then {\Coq} enters the -proof editing mode until the proof is completed. The proof editing -mode essentially contains tactics that are described in chapter -\ref{Tactics}. Besides tactics, there are commands to manage the proof -editing mode. They are described in Chapter~\ref{Proof-handling}. When -the proof is completed it should be validated and put in the -environment using the keyword {\tt Qed}. -\medskip - -\ErrMsg -\begin{enumerate} -\item \errindex{{\ident} already exists} -\end{enumerate} - -\begin{Remarks} -\item Several statements can be simultaneously asserted. -\item Not only other assertions but any vernacular command can be given -while in the process of proving a given assertion. In this case, the command is -understood as if it would have been given before the statements still to be -proved. -\item {\tt Proof} is recommended but can currently be omitted. On the -opposite side, {\tt Qed} (or {\tt Defined}, see below) is mandatory to -validate a proof. -\item Proofs ended by {\tt Qed} are declared opaque. Their content - cannot be unfolded (see \ref{Conversion-tactics}), thus realizing - some form of {\em proof-irrelevance}. To be able to unfold a proof, - the proof should be ended by {\tt Defined} (see below). -\end{Remarks} - -\begin{Variants} -\item \comindex{Defined} - {\tt Proof.} {\dots} {\tt Defined.}\\ - Same as {\tt Proof.} {\dots} {\tt Qed.} but the proof is - then declared transparent, which means that its - content can be explicitly used for type-checking and that it - can be unfolded in conversion tactics (see - \ref{Conversion-tactics}, \ref{Opaque}, \ref{Transparent}). -%Not claimed to be part of Gallina... -%\item {\tt Proof.} {\dots} {\tt Save.}\\ -% Same as {\tt Proof.} {\dots} {\tt Qed.} -%\item {\tt Goal} \type {\dots} {\tt Save} \ident \\ -% Same as {\tt Lemma} \ident {\tt :} \type \dots {\tt Save.} -% This is intended to be used in the interactive mode. -\item \comindex{Admitted} - {\tt Proof.} {\dots} {\tt Admitted.}\\ - Turns the current asserted statement into an axiom and exits the - proof mode. -\end{Variants} - -% Local Variables: -% mode: LaTeX -% TeX-master: "Reference-Manual" -% End: - diff --git a/doc/refman/RefMan-ltac.tex b/doc/refman/RefMan-ltac.tex deleted file mode 100644 index 3ed697d8b..000000000 --- a/doc/refman/RefMan-ltac.tex +++ /dev/null @@ -1,1829 +0,0 @@ -\chapter[The tactic language]{The tactic language\label{TacticLanguage}} -%HEVEA\cutname{ltac.html} - -%\geometry{a4paper,body={5in,8in}} - -This chapter gives a compact documentation of Ltac, the tactic -language available in {\Coq}. We start by giving the syntax, and next, -we present the informal semantics. If you want to know more regarding -this language and especially about its foundations, you can refer -to~\cite{Del00}. Chapter~\ref{Tactics-examples} is devoted to giving -examples of use of this language on small but also with non-trivial -problems. - - -\section{Syntax} - -\def\tacexpr{\textrm{\textsl{expr}}} -\def\tacexprlow{\textrm{\textsl{tacexpr$_1$}}} -\def\tacexprinf{\textrm{\textsl{tacexpr$_2$}}} -\def\tacexprpref{\textrm{\textsl{tacexpr$_3$}}} -\def\atom{\textrm{\textsl{atom}}} -%%\def\recclause{\textrm{\textsl{rec\_clause}}} -\def\letclause{\textrm{\textsl{let\_clause}}} -\def\matchrule{\textrm{\textsl{match\_rule}}} -\def\contextrule{\textrm{\textsl{context\_rule}}} -\def\contexthyp{\textrm{\textsl{context\_hyp}}} -\def\tacarg{\nterm{tacarg}} -\def\cpattern{\nterm{cpattern}} -\def\selector{\textrm{\textsl{selector}}} -\def\toplevelselector{\textrm{\textsl{toplevel\_selector}}} - -The syntax of the tactic language is given Figures~\ref{ltac} -and~\ref{ltac-aux}. See Chapter~\ref{BNF-syntax} for a description of -the BNF metasyntax used in these grammar rules. Various already -defined entries will be used in this chapter: entries -{\naturalnumber}, {\integer}, {\ident}, {\qualid}, {\term}, -{\cpattern} and {\atomictac} represent respectively the natural and -integer numbers, the authorized identificators and qualified names, -{\Coq}'s terms and patterns and all the atomic tactics described in -Chapter~\ref{Tactics}. The syntax of {\cpattern} is the same as that -of terms, but it is extended with pattern matching metavariables. In -{\cpattern}, a pattern-matching metavariable is represented with the -syntax {\tt ?id} where {\tt id} is an {\ident}. The notation {\tt \_} -can also be used to denote metavariable whose instance is -irrelevant. In the notation {\tt ?id}, the identifier allows us to -keep instantiations and to make constraints whereas {\tt \_} shows -that we are not interested in what will be matched. On the right hand -side of pattern-matching clauses, the named metavariable are used -without the question mark prefix. There is also a special notation for -second-order pattern-matching problems: in an applicative pattern of -the form {\tt @?id id$_1$ \ldots id$_n$}, the variable {\tt id} -matches any complex expression with (possible) dependencies in the -variables {\tt id$_1$ \ldots id$_n$} and returns a functional term of -the form {\tt fun id$_1$ \ldots id$_n$ => {\term}}. - - -The main entry of the grammar is {\tacexpr}. This language is used in -proof mode but it can also be used in toplevel definitions as shown in -Figure~\ref{ltactop}. - -\begin{Remarks} -\item The infix tacticals ``\dots\ {\tt ||} \dots'', ``\dots\ {\tt +} - \dots'', and ``\dots\ {\tt ;} \dots'' are associative. - -\item In {\tacarg}, there is an overlap between {\qualid} as a -direct tactic argument and {\qualid} as a particular case of -{\term}. The resolution is done by first looking for a reference of -the tactic language and if it fails, for a reference to a term. To -force the resolution as a reference of the tactic language, use the -form {\tt ltac :} {\qualid}. To force the resolution as a reference to -a term, use the syntax {\tt ({\qualid})}. - -\item As shown by the figure, tactical {\tt ||} binds more than the -prefix tacticals {\tt try}, {\tt repeat}, {\tt do} and -{\tt abstract} which themselves bind more than the postfix tactical -``{\tt \dots\ ;[ \dots\ ]}'' which binds more than ``\dots\ {\tt ;} -\dots''. - -For instance -\begin{quote} -{\tt try repeat \tac$_1$ || - \tac$_2$;\tac$_3$;[\tac$_{31}$|\dots|\tac$_{3n}$];\tac$_4$.} -\end{quote} -is understood as -\begin{quote} -{\tt (try (repeat (\tac$_1$ || \tac$_2$)));} \\ -{\tt ((\tac$_3$;[\tac$_{31}$|\dots|\tac$_{3n}$]);\tac$_4$).} -\end{quote} -\end{Remarks} - - -\begin{figure}[htbp] -\begin{centerframe} -\begin{tabular}{lcl} -{\tacexpr} & ::= & - {\tacexpr} {\tt ;} {\tacexpr}\\ -& | & {\tt [>} \nelist{\tacexpr}{|} {\tt ]}\\ -& | & {\tacexpr} {\tt ; [} \nelist{\tacexpr}{|} {\tt ]}\\ -& | & {\tacexprpref}\\ -\\ -{\tacexprpref} & ::= & - {\tt do} {\it (}{\naturalnumber} {\it |} {\ident}{\it )} {\tacexprpref}\\ -& | & {\tt progress} {\tacexprpref}\\ -& | & {\tt repeat} {\tacexprpref}\\ -& | & {\tt try} {\tacexprpref}\\ -& | & {\tt once} {\tacexprpref}\\ -& | & {\tt exactly\_once} {\tacexprpref}\\ -& | & {\tt timeout} {\it (}{\naturalnumber} {\it |} {\ident}{\it )} {\tacexprpref}\\ -& | & {\tt time} \zeroone{\qstring} {\tacexprpref}\\ -& | & {\tt only} {\selector} {\tt :} {\tacexprpref}\\ -& | & {\tacexprinf} \\ -\\ -{\tacexprinf} & ::= & - {\tacexprlow} {\tt ||} {\tacexprpref}\\ -& | & {\tacexprlow} {\tt +} {\tacexprpref}\\ -& | & {\tt tryif} {\tacexprlow} {\tt then} {\tacexprlow} {\tt else} {\tacexprlow}\\ -& | & {\tacexprlow}\\ -\\ -{\tacexprlow} & ::= & -{\tt fun} \nelist{\name}{} {\tt =>} {\atom}\\ -& | & -{\tt let} \zeroone{\tt rec} \nelist{\letclause}{\tt with} {\tt in} -{\atom}\\ -& | & -{\tt match goal with} \nelist{\contextrule}{\tt |} {\tt end}\\ -& | & -{\tt match reverse goal with} \nelist{\contextrule}{\tt |} {\tt end}\\ -& | & -{\tt match} {\tacexpr} {\tt with} \nelist{\matchrule}{\tt |} {\tt end}\\ -& | & -{\tt lazymatch goal with} \nelist{\contextrule}{\tt |} {\tt end}\\ -& | & -{\tt lazymatch reverse goal with} \nelist{\contextrule}{\tt |} {\tt end}\\ -& | & -{\tt lazymatch} {\tacexpr} {\tt with} \nelist{\matchrule}{\tt |} {\tt end}\\ -& | & -{\tt multimatch goal with} \nelist{\contextrule}{\tt |} {\tt end}\\ -& | & -{\tt multimatch reverse goal with} \nelist{\contextrule}{\tt |} {\tt end}\\ -& | & -{\tt multimatch} {\tacexpr} {\tt with} \nelist{\matchrule}{\tt |} {\tt end}\\ -& | & {\tt abstract} {\atom}\\ -& | & {\tt abstract} {\atom} {\tt using} {\ident} \\ -& | & {\tt first [} \nelist{\tacexpr}{\tt |} {\tt ]}\\ -& | & {\tt solve [} \nelist{\tacexpr}{\tt |} {\tt ]}\\ -& | & {\tt idtac} \sequence{\messagetoken}{}\\ -& | & {\tt fail} \zeroone{\naturalnumber} \sequence{\messagetoken}{}\\ -& | & {\tt gfail} \zeroone{\naturalnumber} \sequence{\messagetoken}{}\\ -& | & {\tt fresh} ~|~ {\tt fresh} {\qstring}|~ {\tt fresh} {\qualid}\\ -& | & {\tt context} {\ident} {\tt [} {\term} {\tt ]}\\ -& | & {\tt eval} {\nterm{redexpr}} {\tt in} {\term}\\ -& | & {\tt type of} {\term}\\ -& | & {\tt external} {\qstring} {\qstring} \nelist{\tacarg}{}\\ -& | & {\tt constr :} {\term}\\ -& | & {\tt uconstr :} {\term}\\ -& | & {\tt type\_term} {\term}\\ -& | & {\tt numgoals} \\ -& | & {\tt guard} {\it test}\\ -& | & {\tt assert\_fails} {\tacexprpref}\\ -& | & {\tt assert\_succeds} {\tacexprpref}\\ -& | & \atomictac\\ -& | & {\qualid} \nelist{\tacarg}{}\\ -& | & {\atom} -\end{tabular} -\end{centerframe} -\caption{Syntax of the tactic language} -\label{ltac} -\end{figure} - - - -\begin{figure}[htbp] -\begin{centerframe} -\begin{tabular}{lcl} -{\atom} & ::= & - {\qualid} \\ -& | & ()\\ -& | & {\integer}\\ -& | & {\tt (} {\tacexpr} {\tt )}\\ -\\ -{\messagetoken}\!\!\!\!\!\! & ::= & {\qstring} ~|~ {\ident} ~|~ {\integer} \\ -\\ -\tacarg & ::= & - {\qualid}\\ -& $|$ & {\tt ()} \\ -& $|$ & {\tt ltac :} {\atom}\\ -& $|$ & {\term}\\ -\\ -\letclause & ::= & {\ident} \sequence{\name}{} {\tt :=} {\tacexpr}\\ -\\ -\contextrule & ::= & - \nelist{\contexthyp}{\tt ,} {\tt |-}{\cpattern} {\tt =>} {\tacexpr}\\ -& $|$ & {\tt |-} {\cpattern} {\tt =>} {\tacexpr}\\ -& $|$ & {\tt \_ =>} {\tacexpr}\\ -\\ -\contexthyp & ::= & {\name} {\tt :} {\cpattern}\\ - & $|$ & {\name} {\tt :=} {\cpattern} \zeroone{{\tt :} {\cpattern}}\\ -\\ -\matchrule & ::= & - {\cpattern} {\tt =>} {\tacexpr}\\ -& $|$ & {\tt context} {\zeroone{\ident}} {\tt [} {\cpattern} {\tt ]} - {\tt =>} {\tacexpr}\\ -& $|$ & {\tt \_ =>} {\tacexpr}\\ -\\ -{\it test} & ::= & - {\integer} {\tt \,=\,} {\integer}\\ -& $|$ & {\integer} {\tt \,<\,} {\integer}\\ -& $|$ & {\integer} {\tt <=} {\integer}\\ -& $|$ & {\integer} {\tt \,>\,} {\integer}\\ -& $|$ & {\integer} {\tt >=} {\integer}\\ -\\ -\selector & ::= & - [{\ident}]\\ -& $|$ & {\integer}\\ -& $|$ & \nelist{{\it (}{\integer} {\it |} {\integer} {\tt -} {\integer}{\it )}} - {\tt ,}\\ -\\ -\toplevelselector & ::= & - \selector\\ -& $|$ & {\tt all}\\ -& $|$ & {\tt par} -\end{tabular} -\end{centerframe} -\caption{Syntax of the tactic language (continued)} -\label{ltac-aux} -\end{figure} - -\begin{figure}[ht] -\begin{centerframe} -\begin{tabular}{lcl} -\nterm{top} & ::= & \zeroone{\tt Local} {\tt Ltac} \nelist{\nterm{ltac\_def}} {\tt with} \\ -\\ -\nterm{ltac\_def} & ::= & {\ident} \sequence{\ident}{} {\tt :=} -{\tacexpr}\\ -& $|$ &{\qualid} \sequence{\ident}{} {\tt ::=}{\tacexpr} -\end{tabular} -\end{centerframe} -\caption{Tactic toplevel definitions} -\label{ltactop} -\end{figure} - - -%% -%% Semantics -%% -\section{Semantics} -%\index[tactic]{Tacticals} -\index{Tacticals} -%\label{Tacticals} - -Tactic expressions can only be applied in the context of a proof. The -evaluation yields either a term, an integer or a tactic. Intermediary -results can be terms or integers but the final result must be a tactic -which is then applied to the focused goals. - -There is a special case for {\tt match goal} expressions of which -the clauses evaluate to tactics. Such expressions can only be used as -end result of a tactic expression (never as argument of a non recursive local -definition or of an application). - -The rest of this section explains the semantics of every construction -of Ltac. - - -%% \subsection{Values} - -%% Values are given by Figure~\ref{ltacval}. All these values are tactic values, -%% i.e. to be applied to a goal, except {\tt Fun}, {\tt Rec} and $arg$ values. - -%% \begin{figure}[ht] -%% \noindent{}\framebox[6in][l] -%% {\parbox{6in} -%% {\begin{center} -%% \begin{tabular}{lp{0.1in}l} -%% $vexpr$ & ::= & $vexpr$ {\tt ;} $vexpr$\\ -%% & | & $vexpr$ {\tt ; [} {\it (}$vexpr$ {\tt |}{\it )}$^*$ $vexpr$ {\tt -%% ]}\\ -%% & | & $vatom$\\ -%% \\ -%% $vatom$ & ::= & {\tt Fun} \nelist{\inputfun}{} {\tt ->} {\tacexpr}\\ -%% %& | & {\tt Rec} \recclause\\ -%% & | & -%% {\tt Rec} \nelist{\recclause}{\tt And} {\tt In} -%% {\tacexpr}\\ -%% & | & -%% {\tt Match Context With} {\it (}$context\_rule$ {\tt |}{\it )}$^*$ -%% $context\_rule$\\ -%% & | & {\tt (} $vexpr$ {\tt )}\\ -%% & | & $vatom$ {\tt Orelse} $vatom$\\ -%% & | & {\tt Do} {\it (}{\naturalnumber} {\it |} {\ident}{\it )} $vatom$\\ -%% & | & {\tt Repeat} $vatom$\\ -%% & | & {\tt Try} $vatom$\\ -%% & | & {\tt First [} {\it (}$vexpr$ {\tt |}{\it )}$^*$ $vexpr$ {\tt ]}\\ -%% & | & {\tt Solve [} {\it (}$vexpr$ {\tt |}{\it )}$^*$ $vexpr$ {\tt ]}\\ -%% & | & {\tt Idtac}\\ -%% & | & {\tt Fail}\\ -%% & | & {\primitivetactic}\\ -%% & | & $arg$ -%% \end{tabular} -%% \end{center}}} -%% \caption{Values of ${\cal L}_{tac}$} -%% \label{ltacval} -%% \end{figure} - -%% \subsection{Evaluation} - -\subsubsection[Sequence]{Sequence\tacindex{;} -\index{Tacticals!;@{\tt {\tac$_1$};\tac$_2$}}} - -A sequence is an expression of the following form: -\begin{quote} -{\tacexpr}$_1$ {\tt ;} {\tacexpr}$_2$ -\end{quote} -The expression {\tacexpr}$_1$ is evaluated to $v_1$, which must be -a tactic value. The tactic $v_1$ is applied to the current goal, -possibly producing more goals. Then {\tacexpr}$_2$ is evaluated to -produce $v_2$, which must be a tactic value. The tactic $v_2$ is applied to -all the goals produced by the prior application. Sequence is associative. - -\subsubsection[Local application of tactics]{Local application of tactics\tacindex{[>\ldots$\mid$\ldots$\mid$\ldots]}\tacindex{;[\ldots$\mid$\ldots$\mid$\ldots]}\index{Tacticals![> \mid ]@{\tt {\tac$_0$};[{\tac$_1$}$\mid$\ldots$\mid$\tac$_n$]}}\index{Tacticals!; [ \mid ]@{\tt {\tac$_0$};[{\tac$_1$}$\mid$\ldots$\mid$\tac$_n$]}}} -%\tacindex{; [ | ]} -%\index{; [ | ]@{\tt ;[\ldots$\mid$\ldots$\mid$\ldots]}} - -Different tactics can be applied to the different goals using the following form: -\begin{quote} -{\tt [ >} {\tacexpr}$_1$ {\tt |} $...$ {\tt |} {\tacexpr}$_n$ {\tt ]} -\end{quote} -The expressions {\tacexpr}$_i$ are evaluated to $v_i$, for $i=0,...,n$ -and all have to be tactics. The $v_i$ is applied to the $i$-th goal, -for $=1,...,n$. It fails if the number of focused goals is not exactly $n$. - -\begin{Variants} - \item If no tactic is given for the $i$-th goal, it behaves as if - the tactic {\tt idtac} were given. For instance, {\tt [~> | auto - ]} is a shortcut for {\tt [ > idtac | auto ]}. - - \item {\tt [ >} {\tacexpr}$_1$ {\tt |} $...$ {\tt |} - {\tacexpr}$_i$ {\tt |} {\tacexpr} {\tt ..} {\tt |} - {\tacexpr}$_{i+1+j}$ {\tt |} $...$ {\tt |} {\tacexpr}$_n$ {\tt ]} - - In this variant, {\tt expr} is used for each goal numbered from - $i+1$ to $i+j$ (assuming $n$ is the number of goals). - - Note that {\tt ..} is part of the syntax, while $...$ is the meta-symbol used - to describe a list of {\tacexpr} of arbitrary length. - goals numbered from $i+1$ to $i+j$. - - \item {\tt [ >} {\tacexpr}$_1$ {\tt |} $...$ {\tt |} - {\tacexpr}$_i$ {\tt |} {\tt ..} {\tt |} {\tacexpr}$_{i+1+j}$ {\tt |} - $...$ {\tt |} {\tacexpr}$_n$ {\tt ]} - - In this variant, {\tt idtac} is used for the goals numbered from - $i+1$ to $i+j$. - - \item {\tt [ >} {\tacexpr} {\tt ..} {\tt ]} - - In this variant, the tactic {\tacexpr} is applied independently to - each of the goals, rather than globally. In particular, if there - are no goal, the tactic is not run at all. A tactic which - expects multiple goals, such as {\tt swap}, would act as if a single - goal is focused. - - \item {\tacexpr} {\tt ; [ } {\tacexpr}$_1$ {\tt |} $...$ {\tt |} {\tacexpr}$_n$ {\tt ]} - - This variant of local tactic application is paired with a - sequence. In this variant, $n$ must be the number of goals - generated by the application of {\tacexpr} to each of the - individual goals independently. All the above variants work in - this form too. Formally, {\tacexpr} {\tt ; [} $...$ {\tt ]} is - equivalent to - \begin{quote} - {\tt [ >} {\tacexpr} {\tt ; [ >} $...$ {\tt ]} {\tt ..} {\tt ]} - \end{quote} - -\end{Variants} - -\subsubsection[Goal selectors]{Goal selectors\label{ltac:selector} -\tacindex{\tt :}\index{Tacticals!:@{\tt :}}} - -We can restrict the application of a tactic to a subset of -the currently focused goals with: -\begin{quote} - {\toplevelselector} {\tt :} {\tacexpr} -\end{quote} -We can also use selectors as a tactical, which allows to use them nested in -a tactic expression, by using the keyword {\tt only}: -\begin{quote} - {\tt only} {\selector} {\tt :} {\tacexpr} -\end{quote} -When selecting several goals, the tactic {\tacexpr} is applied globally to -all selected goals. - -\begin{Variants} - \item{} [{\ident}] {\tt :} {\tacexpr} - - In this variant, {\tacexpr} is applied locally to a goal - previously named by the user (see~\ref{ExistentialVariables}). - - \item {\num} {\tt :} {\tacexpr} - - In this variant, {\tacexpr} is applied locally to the - {\num}-th goal. - - \item $n_1$-$m_1$, \dots, $n_k$-$m_k$ {\tt :} {\tacexpr} - - In this variant, {\tacexpr} is applied globally to the subset - of goals described by the given ranges. You can write a single - $n$ as a shortcut for $n$-$n$ when specifying multiple ranges. - - \item {\tt all:} {\tacexpr} - - In this variant, {\tacexpr} is applied to all focused goals. - {\tt all:} can only be used at the toplevel of a tactic expression. - - \item {\tt par:} {\tacexpr} - - In this variant, {\tacexpr} is applied to all focused goals - in parallel. The number of workers can be controlled via the - command line option {\tt -async-proofs-tac-j} taking as argument - the desired number of workers. Limitations: {\tt par: } only works - on goals containing no existential variables and {\tacexpr} must - either solve the goal completely or do nothing (i.e. it cannot make - some progress). - {\tt par:} can only be used at the toplevel of a tactic expression. - -\end{Variants} - -\ErrMsg \errindex{No such goal} - -\subsubsection[For loop]{For loop\tacindex{do} -\index{Tacticals!do@{\tt do}}} - -There is a for loop that repeats a tactic {\num} times: -\begin{quote} -{\tt do} {\num} {\tacexpr} -\end{quote} -{\tacexpr} is evaluated to $v$ which must be a tactic value. -This tactic value $v$ is -applied {\num} times. Supposing ${\num}>1$, after the first -application of $v$, $v$ is applied, at least once, to the generated -subgoals and so on. It fails if the application of $v$ fails before -the {\num} applications have been completed. - -\subsubsection[Repeat loop]{Repeat loop\tacindex{repeat} -\index{Tacticals!repeat@{\tt repeat}}} - -We have a repeat loop with: -\begin{quote} -{\tt repeat} {\tacexpr} -\end{quote} -{\tacexpr} is evaluated to $v$. If $v$ denotes a tactic, this tactic -is applied to each focused goal independently. If the application -succeeds, the tactic is applied recursively to all the generated subgoals -until it eventually fails. The recursion stops in a subgoal when the -tactic has failed \emph{to make progress}. The tactic {\tt repeat - {\tacexpr}} itself never fails. - -\subsubsection[Error catching]{Error catching\tacindex{try} -\index{Tacticals!try@{\tt try}}} - -We can catch the tactic errors with: -\begin{quote} -{\tt try} {\tacexpr} -\end{quote} -{\tacexpr} is evaluated to $v$ which must be a tactic value. -The tactic value $v$ is -applied to each focused goal independently. If the application of $v$ -fails in a goal, it catches the error and leaves the goal -unchanged. If the level of the exception is positive, then the -exception is re-raised with its level decremented. - -\subsubsection[Detecting progress]{Detecting progress\tacindex{progress}} - -We can check if a tactic made progress with: -\begin{quote} -{\tt progress} {\tacexpr} -\end{quote} -{\tacexpr} is evaluated to $v$ which must be a tactic value. -The tactic value $v$ is -applied to each focued subgoal independently. If the application of -$v$ to one of the focused subgoal produced subgoals equal to the -initial goals (up to syntactical equality), then an error of level 0 -is raised. - -\ErrMsg \errindex{Failed to progress} - -\subsubsection[Backtracking branching]{Backtracking branching\tacindex{$+$} -\index{Tacticals!or@{\tt $+$}}} - -We can branch with the following structure: -\begin{quote} -{\tacexpr}$_1$ {\tt +} {\tacexpr}$_2$ -\end{quote} -{\tacexpr}$_1$ and {\tacexpr}$_2$ are evaluated to $v_1$ and -$v_2$ which must be tactic values. The tactic value $v_1$ is applied to each -focused goal independently and if it fails or a later tactic fails, -then the proof backtracks to the current goal and $v_2$ is applied. - -Tactics can be seen as having several successes. When a tactic fails -it asks for more successes of the prior tactics. {\tacexpr}$_1$ {\tt - +} {\tacexpr}$_2$ has all the successes of $v_1$ followed by all the -successes of $v_2$. Algebraically, ({\tacexpr}$_1$ {\tt +} -{\tacexpr}$_2$);{\tacexpr}$_3$ $=$ ({\tacexpr}$_1$;{\tacexpr}$_3$) -{\tt +} ({\tacexpr}$_2$;{\tacexpr}$_3$). - -Branching is left-associative. - -\subsubsection[First tactic to work]{First tactic to work\tacindex{first} -\index{Tacticals!first@{\tt first}}} - -Backtracking branching may be too expensive. In this case we may -restrict to a local, left biased, branching and consider the first -tactic to work (i.e. which does not fail) among a panel of tactics: -\begin{quote} -{\tt first [} {\tacexpr}$_1$ {\tt |} $...$ {\tt |} {\tacexpr}$_n$ {\tt ]} -\end{quote} -{\tacexpr}$_i$ are evaluated to $v_i$ and $v_i$ must be tactic values, -for $i=1,...,n$. Supposing $n>1$, it applies, in each focused goal -independently, $v_1$, if it works, it stops otherwise it tries to -apply $v_2$ and so on. It fails when there is no applicable tactic. In -other words, {\tt first [} {\tacexpr}$_1$ {\tt |} $...$ {\tt |} - {\tacexpr}$_n$ {\tt ]} behaves, in each goal, as the the first $v_i$ -to have \emph{at least} one success. - -\ErrMsg \errindex{No applicable tactic} - -\variant {\tt first {\tacexpr}} - -This is an Ltac alias that gives a primitive access to the {\tt first} tactical -as a Ltac definition without going through a parsing rule. It expects to be -given a list of tactics through a {\tt Tactic Notation}, allowing to write -notations of the following form. - -\Example - -\begin{quote} -{\tt Tactic Notation "{foo}" tactic\_list(tacs) := first tacs.} -\end{quote} - -\subsubsection[Left-biased branching]{Left-biased branching\tacindex{$\mid\mid$} -\index{Tacticals!orelse@{\tt $\mid\mid$}}} - -Yet another way of branching without backtracking is the following structure: -\begin{quote} -{\tacexpr}$_1$ {\tt ||} {\tacexpr}$_2$ -\end{quote} -{\tacexpr}$_1$ and {\tacexpr}$_2$ are evaluated to $v_1$ and -$v_2$ which must be tactic values. The tactic value $v_1$ is applied in each -subgoal independently and if it fails \emph{to progress} then $v_2$ is -applied. {\tacexpr}$_1$ {\tt ||} {\tacexpr}$_2$ is equivalent to {\tt - first [} {\tt progress} {\tacexpr}$_1$ {\tt |} - {\tacexpr}$_2$ {\tt ]} (except that if it fails, it fails like -$v_2$). Branching is left-associative. - -\subsubsection[Generalized biased branching]{Generalized biased branching\tacindex{tryif} -\index{Tacticals!tryif@{\tt tryif}}} - -The tactic -\begin{quote} -{\tt tryif {\tacexpr}$_1$ then {\tacexpr}$_2$ else {\tacexpr}$_3$} -\end{quote} -is a generalization of the biased-branching tactics above. The -expression {\tacexpr}$_1$ is evaluated to $v_1$, which is then applied -to each subgoal independently. For each goal where $v_1$ succeeds at -least once, {\tacexpr}$_2$ is evaluated to $v_2$ which is then applied -collectively to the generated subgoals. The $v_2$ tactic can trigger -backtracking points in $v_1$: where $v_1$ succeeds at least once, {\tt - tryif {\tacexpr}$_1$ then {\tacexpr}$_2$ else {\tacexpr}$_3$} is -equivalent to $v_1;v_2$. In each of the goals where $v_1$ does not -succeed at least once, {\tacexpr}$_3$ is evaluated in $v_3$ which is -is then applied to the goal. - -\subsubsection[Soft cut]{Soft cut\tacindex{once}\index{Tacticals!once@{\tt once}}} - -Another way of restricting backtracking is to restrict a tactic to a -single success \emph{a posteriori}: -\begin{quote} -{\tt once} {\tacexpr} -\end{quote} -{\tacexpr} is evaluated to $v$ which must be a tactic value. -The tactic value $v$ is -applied but only its first success is used. If $v$ fails, {\tt once} -{\tacexpr} fails like $v$. If $v$ has a least one success, {\tt once} -{\tacexpr} succeeds once, but cannot produce more successes. - -\subsubsection[Checking the successes]{Checking the successes\tacindex{exactly\_once}\index{Tacticals!exactly\_once@{\tt exactly\_once}}} - -Coq provides an experimental way to check that a tactic has \emph{exactly one} success: -\begin{quote} -{\tt exactly\_once} {\tacexpr} -\end{quote} -{\tacexpr} is evaluated to $v$ which must be a tactic value. -The tactic value $v$ is -applied if it has at most one success. If $v$ fails, {\tt - exactly\_once} {\tacexpr} fails like $v$. If $v$ has a exactly one -success, {\tt exactly\_once} {\tacexpr} succeeds like $v$. If $v$ has -two or more successes, {\tt exactly\_once} {\tacexpr} fails. - -The experimental status of this tactic pertains to the fact if $v$ performs side effects, they may occur in a unpredictable way. Indeed, normally $v$ would only be executed up to the first success until backtracking is needed, however {\tt exactly\_once} needs to look ahead to see whether a second success exists, and may run further effects immediately. - -\ErrMsg \errindex{This tactic has more than one success} - -\subsubsection[Checking the failure]{Checking the failure\tacindex{assert\_fails}\index{Tacticals!assert\_fails@{\tt assert\_fails}}} - -Coq provides a derived tactic to check that a tactic \emph{fails}: -\begin{quote} -{\tt assert\_fails} {\tacexpr} -\end{quote} -This behaves like {\tt tryif {\tacexpr} then fail 0 tac "succeeds" else idtac}. - -\subsubsection[Checking the success]{Checking the success\tacindex{assert\_succeeds}\index{Tacticals!assert\_succeeds@{\tt assert\_succeeds}}} - -Coq provides a derived tactic to check that a tactic has \emph{at least one} success: -\begin{quote} -{\tt assert\_succeeds} {\tacexpr} -\end{quote} -This behaves like {\tt tryif (assert\_fails tac) then fail 0 tac "fails" else idtac}. - -\subsubsection[Solving]{Solving\tacindex{solve} -\index{Tacticals!solve@{\tt solve}}} - -We may consider the first to solve (i.e. which generates no subgoal) among a -panel of tactics: -\begin{quote} -{\tt solve [} {\tacexpr}$_1$ {\tt |} $...$ {\tt |} {\tacexpr}$_n$ {\tt ]} -\end{quote} -{\tacexpr}$_i$ are evaluated to $v_i$ and $v_i$ must be tactic values, -for $i=1,...,n$. Supposing $n>1$, it applies $v_1$ to each goal -independently, if it doesn't solve the goal then it tries to apply -$v_2$ and so on. It fails if there is no solving tactic. - -\ErrMsg \errindex{Cannot solve the goal} - -\variant {\tt solve {\tacexpr}} - -This is an Ltac alias that gives a primitive access to the {\tt solve} tactical. -See the {\tt first} tactical for more information. - -\subsubsection[Identity]{Identity\label{ltac:idtac}\tacindex{idtac} -\index{Tacticals!idtac@{\tt idtac}}} - -The constant {\tt idtac} is the identity tactic: it leaves any goal -unchanged but it appears in the proof script. - -\variant {\tt idtac \nelist{\messagetoken}{}} - -This prints the given tokens. Strings and integers are printed -literally. If a (term) variable is given, its contents are printed. - - -\subsubsection[Failing]{Failing\tacindex{fail} -\index{Tacticals!fail@{\tt fail}} -\tacindex{gfail}\index{Tacticals!gfail@{\tt gfail}}} - -The tactic {\tt fail} is the always-failing tactic: it does not solve -any goal. It is useful for defining other tacticals since it can be -caught by {\tt try}, {\tt repeat}, {\tt match goal}, or the branching -tacticals. The {\tt fail} tactic will, however, succeed if all the -goals have already been solved. - -\begin{Variants} -\item {\tt fail $n$}\\ The number $n$ is the failure level. If no - level is specified, it defaults to $0$. The level is used by {\tt - try}, {\tt repeat}, {\tt match goal} and the branching tacticals. - If $0$, it makes {\tt match goal} considering the next clause - (backtracking). If non zero, the current {\tt match goal} block, - {\tt try}, {\tt repeat}, or branching command is aborted and the - level is decremented. In the case of {\tt +}, a non-zero level skips - the first backtrack point, even if the call to {\tt fail $n$} is not - enclosed in a {\tt +} command, respecting the algebraic identity. - -\item {\tt fail \nelist{\messagetoken}{}}\\ -The given tokens are used for printing the failure message. - -\item {\tt fail $n$ \nelist{\messagetoken}{}}\\ -This is a combination of the previous variants. - -\item {\tt gfail}\\ -This variant fails even if there are no goals left. - -\item {\tt gfail \nelist{\messagetoken}{}}\\ -{\tt gfail $n$ \nelist{\messagetoken}{}}\\ -These variants fail with an error message or an error level even if -there are no goals left. Be careful however if Coq terms have to be -printed as part of the failure: term construction always forces the -tactic into the goals, meaning that if there are no goals when it is -evaluated, a tactic call like {\tt let x:=H in fail 0 x} will succeed. - -\end{Variants} - -\ErrMsg \errindex{Tactic Failure {\it message} (level $n$)}. - -\subsubsection[Timeout]{Timeout\tacindex{timeout} -\index{Tacticals!timeout@{\tt timeout}}} - -We can force a tactic to stop if it has not finished after a certain -amount of time: -\begin{quote} -{\tt timeout} {\num} {\tacexpr} -\end{quote} -{\tacexpr} is evaluated to $v$ which must be a tactic value. -The tactic value $v$ is -applied normally, except that it is interrupted after ${\num}$ seconds -if it is still running. In this case the outcome is a failure. - -Warning: For the moment, {\tt timeout} is based on elapsed time in -seconds, which is very -machine-dependent: a script that works on a quick machine may fail -on a slow one. The converse is even possible if you combine a -{\tt timeout} with some other tacticals. This tactical is hence -proposed only for convenience during debug or other development -phases, we strongly advise you to not leave any {\tt timeout} in -final scripts. Note also that this tactical isn't available on -the native Windows port of Coq. - -\subsubsection{Timing a tactic\tacindex{time} -\index{Tacticals!time@{\tt time}}} - -A tactic execution can be timed: -\begin{quote} - {\tt time} {\qstring} {\tacexpr} -\end{quote} -evaluates {\tacexpr} -and displays the time the tactic expression ran, whether it fails or -successes. In case of several successes, the time for each successive -runs is displayed. Time is in seconds and is machine-dependent. The -{\qstring} argument is optional. When provided, it is used to identify -this particular occurrence of {\tt time}. - -\subsubsection{Timing a tactic that evaluates to a term\tacindex{time\_constr}\tacindex{restart\_timer}\tacindex{finish\_timing} -\index{Tacticals!time\_constr@{\tt time\_constr}}} -\index{Tacticals!restart\_timer@{\tt restart\_timer}} -\index{Tacticals!finish\_timing@{\tt finish\_timing}} - -Tactic expressions that produce terms can be timed with the experimental tactic -\begin{quote} - {\tt time\_constr} {\tacexpr} -\end{quote} -which evaluates {\tacexpr\tt{ ()}} -and displays the time the tactic expression evaluated, assuming successful evaluation. -Time is in seconds and is machine-dependent. - -This tactic currently does not support nesting, and will report times based on the innermost execution. -This is due to the fact that it is implemented using the tactics -\begin{quote} - {\tt restart\_timer} {\qstring} -\end{quote} -and -\begin{quote} - {\tt finish\_timing} ({\qstring}) {\qstring} -\end{quote} -which (re)set and display an optionally named timer, respectively. -The parenthesized {\qstring} argument to {\tt finish\_timing} is also -optional, and determines the label associated with the timer for -printing. - -By copying the definition of {\tt time\_constr} from the standard -library, users can achive support for a fixed pattern of nesting by -passing different {\qstring} parameters to {\tt restart\_timer} and -{\tt finish\_timing} at each level of nesting. For example: - -\begin{coq_example} -Ltac time_constr1 tac := - let eval_early := match goal with _ => restart_timer "(depth 1)" end in - let ret := tac () in - let eval_early := match goal with _ => finish_timing ( "Tactic evaluation" ) "(depth 1)" end in - ret. - -Goal True. - let v := time_constr - ltac:(fun _ => - let x := time_constr1 ltac:(fun _ => constr:(10 * 10)) in - let y := time_constr1 ltac:(fun _ => eval compute in x) in - y) in - pose v. -Abort. -\end{coq_example} - -\subsubsection[Local definitions]{Local definitions\index{Ltac!let@\texttt{let}} -\index{Ltac!let rec@\texttt{let rec}} -\index{let@\texttt{let}!in Ltac} -\index{let rec@\texttt{let rec}!in Ltac}} - -Local definitions can be done as follows: -\begin{quote} -{\tt let} {\ident}$_1$ {\tt :=} {\tacexpr}$_1$\\ -{\tt with} {\ident}$_2$ {\tt :=} {\tacexpr}$_2$\\ -...\\ -{\tt with} {\ident}$_n$ {\tt :=} {\tacexpr}$_n$ {\tt in}\\ -{\tacexpr} -\end{quote} -each {\tacexpr}$_i$ is evaluated to $v_i$, then, {\tacexpr} is -evaluated by substituting $v_i$ to each occurrence of {\ident}$_i$, -for $i=1,...,n$. There is no dependencies between the {\tacexpr}$_i$ -and the {\ident}$_i$. - -Local definitions can be recursive by using {\tt let rec} instead of -{\tt let}. In this latter case, the definitions are evaluated lazily -so that the {\tt rec} keyword can be used also in non recursive cases -so as to avoid the eager evaluation of local definitions. - -\subsubsection{Application} - -An application is an expression of the following form: -\begin{quote} -{\qualid} {\tacarg}$_1$ ... {\tacarg}$_n$ -\end{quote} -The reference {\qualid} must be bound to some defined tactic -definition expecting at least $n$ arguments. The expressions -{\tacexpr}$_i$ are evaluated to $v_i$, for $i=1,...,n$. -%If {\tacexpr} is a {\tt Fun} or {\tt Rec} value then the body is evaluated by -%substituting $v_i$ to the formal parameters, for $i=1,...,n$. For recursive -%clauses, the bodies are lazily substituted (when an identifier to be evaluated -%is the name of a recursive clause). - -%\subsection{Application of tactic values} - -\subsubsection[Function construction]{Function construction\index{fun@\texttt{fun}!in Ltac} -\index{Ltac!fun@\texttt{fun}}} - -A parameterized tactic can be built anonymously (without resorting to -local definitions) with: -\begin{quote} -{\tt fun} {\ident${}_1$} ... {\ident${}_n$} {\tt =>} {\tacexpr} -\end{quote} -Indeed, local definitions of functions are a syntactic sugar for -binding a {\tt fun} tactic to an identifier. - -\subsubsection[Pattern matching on terms]{Pattern matching on terms\index{Ltac!match@\texttt{match}} -\index{match@\texttt{match}!in Ltac}} - -We can carry out pattern matching on terms with: -\begin{quote} -{\tt match} {\tacexpr} {\tt with}\\ -~~~{\cpattern}$_1$ {\tt =>} {\tacexpr}$_1$\\ -~{\tt |} {\cpattern}$_2$ {\tt =>} {\tacexpr}$_2$\\ -~...\\ -~{\tt |} {\cpattern}$_n$ {\tt =>} {\tacexpr}$_n$\\ -~{\tt |} {\tt \_} {\tt =>} {\tacexpr}$_{n+1}$\\ -{\tt end} -\end{quote} -The expression {\tacexpr} is evaluated and should yield a term which -is matched against {\cpattern}$_1$. The matching is non-linear: if a -metavariable occurs more than once, it should match the same -expression every time. It is first-order except on the -variables of the form {\tt @?id} that occur in head position of an -application. For these variables, the matching is second-order and -returns a functional term. - -Alternatively, when a metavariable of the form {\tt ?id} occurs under -binders, say $x_1$, \ldots, $x_n$ and the expression matches, the -metavariable is instantiated by a term which can then be used in any -context which also binds the variables $x_1$, \ldots, $x_n$ with -same types. This provides with a primitive form of matching -under context which does not require manipulating a functional term. - -If the matching with {\cpattern}$_1$ succeeds, then {\tacexpr}$_1$ is -evaluated into some value by substituting the pattern matching -instantiations to the metavariables. If {\tacexpr}$_1$ evaluates to a -tactic and the {\tt match} expression is in position to be applied to -a goal (e.g. it is not bound to a variable by a {\tt let in}), then -this tactic is applied. If the tactic succeeds, the list of resulting -subgoals is the result of the {\tt match} expression. If -{\tacexpr}$_1$ does not evaluate to a tactic or if the {\tt match} -expression is not in position to be applied to a goal, then the result -of the evaluation of {\tacexpr}$_1$ is the result of the {\tt match} -expression. - -If the matching with {\cpattern}$_1$ fails, or if it succeeds but the -evaluation of {\tacexpr}$_1$ fails, or if the evaluation of -{\tacexpr}$_1$ succeeds but returns a tactic in execution position -whose execution fails, then {\cpattern}$_2$ is used and so on. The -pattern {\_} matches any term and shunts all remaining patterns if -any. If all clauses fail (in particular, there is no pattern {\_}) -then a no-matching-clause error is raised. - -Failures in subsequent tactics do not cause backtracking to select new -branches or inside the right-hand side of the selected branch even if -it has backtracking points. - -\begin{ErrMsgs} - -\item \errindex{No matching clauses for match} - - No pattern can be used and, in particular, there is no {\tt \_} pattern. - -\item \errindex{Argument of match does not evaluate to a term} - - This happens when {\tacexpr} does not denote a term. - -\end{ErrMsgs} - -\begin{Variants} - -\item \index{multimatch@\texttt{multimatch}!in Ltac} -\index{Ltac!multimatch@\texttt{multimatch}} -Using {\tt multimatch} instead of {\tt match} will allow subsequent -tactics to backtrack into a right-hand side tactic which has -backtracking points left and trigger the selection of a new matching -branch when all the backtracking points of the right-hand side have -been consumed. - -The syntax {\tt match \ldots} is, in fact, a shorthand for -{\tt once multimatch \ldots}. - -\item \index{lazymatch@\texttt{lazymatch}!in Ltac} -\index{Ltac!lazymatch@\texttt{lazymatch}} -Using {\tt lazymatch} instead of {\tt match} will perform the same -pattern matching procedure but will commit to the first matching -branch rather than trying a new matching if the right-hand side -fails. If the right-hand side of the selected branch is a tactic with -backtracking points, then subsequent failures cause this tactic to -backtrack. - -\item \index{context@\texttt{context}!in pattern} -There is a special form of patterns to match a subterm against the -pattern: -\begin{quote} -{\tt context} {\ident} {\tt [} {\cpattern} {\tt ]} -\end{quote} -It matches any term with a subterm matching {\cpattern}. If there is -a match, the optional {\ident} is assigned the ``matched context'', i.e. -the initial term where the matched subterm is replaced by a -hole. The example below will show how to use such term contexts. - -If the evaluation of the right-hand-side of a valid match fails, the -next matching subterm is tried. If no further subterm matches, the -next clause is tried. Matching subterms are considered top-bottom and -from left to right (with respect to the raw printing obtained by -setting option {\tt Printing All}, see Section~\ref{SetPrintingAll}). - -\begin{coq_example} -Ltac f x := - match x with - context f [S ?X] => - idtac X; (* To display the evaluation order *) - assert (p := eq_refl 1 : X=1); (* To filter the case X=1 *) - let x:= context f[O] in assert (x=O) (* To observe the context *) - end. -Goal True. -f (3+4). -\end{coq_example} - -\end{Variants} - -\subsubsection[Pattern matching on goals]{Pattern matching on goals\index{Ltac!match goal@\texttt{match goal}}\label{ltac-match-goal} -\index{Ltac!match reverse goal@\texttt{match reverse goal}} -\index{match goal@\texttt{match goal}!in Ltac} -\index{match reverse goal@\texttt{match reverse goal}!in Ltac}} - -We can make pattern matching on goals using the following expression: -\begin{quote} -\begin{tabbing} -{\tt match goal with}\\ -~~\={\tt |} $hyp_{1,1}${\tt ,}...{\tt ,}$hyp_{1,m_1}$ - ~~{\tt |-}{\cpattern}$_1${\tt =>} {\tacexpr}$_1$\\ - \>{\tt |} $hyp_{2,1}${\tt ,}...{\tt ,}$hyp_{2,m_2}$ - ~~{\tt |-}{\cpattern}$_2${\tt =>} {\tacexpr}$_2$\\ -~~...\\ - \>{\tt |} $hyp_{n,1}${\tt ,}...{\tt ,}$hyp_{n,m_n}$ - ~~{\tt |-}{\cpattern}$_n${\tt =>} {\tacexpr}$_n$\\ - \>{\tt |\_}~~~~{\tt =>} {\tacexpr}$_{n+1}$\\ -{\tt end} -\end{tabbing} -\end{quote} - -If each hypothesis pattern $hyp_{1,i}$, with $i=1,...,m_1$ -is matched (non-linear first-order unification) by an hypothesis of -the goal and if {\cpattern}$_1$ is matched by the conclusion of the -goal, then {\tacexpr}$_1$ is evaluated to $v_1$ by substituting the -pattern matching to the metavariables and the real hypothesis names -bound to the possible hypothesis names occurring in the hypothesis -patterns. If $v_1$ is a tactic value, then it is applied to the -goal. If this application fails, then another combination of -hypotheses is tried with the same proof context pattern. If there is -no other combination of hypotheses then the second proof context -pattern is tried and so on. If the next to last proof context pattern -fails then {\tacexpr}$_{n+1}$ is evaluated to $v_{n+1}$ and $v_{n+1}$ -is applied. Note also that matching against subterms (using the {\tt -context} {\ident} {\tt [} {\cpattern} {\tt ]}) is available and is -also subject to yielding several matchings. - -Failures in subsequent tactics do not cause backtracking to select new -branches or combinations of hypotheses, or inside the right-hand side -of the selected branch even if it has backtracking points. - -\ErrMsg \errindex{No matching clauses for match goal} - -No clause succeeds, i.e. all matching patterns, if any, -fail at the application of the right-hand-side. - -\medskip - -It is important to know that each hypothesis of the goal can be -matched by at most one hypothesis pattern. The order of matching is -the following: hypothesis patterns are examined from the right to the -left (i.e. $hyp_{i,m_i}$ before $hyp_{i,1}$). For each hypothesis -pattern, the goal hypothesis are matched in order (fresher hypothesis -first), but it possible to reverse this order (older first) with -the {\tt match reverse goal with} variant. - -\variant - -\index{multimatch goal@\texttt{multimatch goal}!in Ltac} -\index{Ltac!multimatch goal@\texttt{multimatch goal}} -\index{multimatch reverse goal@\texttt{multimatch reverse goal}!in Ltac} -\index{Ltac!multimatch reverse goal@\texttt{multimatch reverse goal}} - -Using {\tt multimatch} instead of {\tt match} will allow subsequent -tactics to backtrack into a right-hand side tactic which has -backtracking points left and trigger the selection of a new matching -branch or combination of hypotheses when all the backtracking points -of the right-hand side have been consumed. - -The syntax {\tt match [reverse] goal \ldots} is, in fact, a shorthand for -{\tt once multimatch [reverse] goal \ldots}. - -\index{lazymatch goal@\texttt{lazymatch goal}!in Ltac} -\index{Ltac!lazymatch goal@\texttt{lazymatch goal}} -\index{lazymatch reverse goal@\texttt{lazymatch reverse goal}!in Ltac} -\index{Ltac!lazymatch reverse goal@\texttt{lazymatch reverse goal}} -Using {\tt lazymatch} instead of {\tt match} will perform the same -pattern matching procedure but will commit to the first matching -branch with the first matching combination of hypotheses rather than -trying a new matching if the right-hand side fails. If the right-hand -side of the selected branch is a tactic with backtracking points, then -subsequent failures cause this tactic to backtrack. - -\subsubsection[Filling a term context]{Filling a term context\index{context@\texttt{context}!in expression}} - -The following expression is not a tactic in the sense that it does not -produce subgoals but generates a term to be used in tactic -expressions: -\begin{quote} -{\tt context} {\ident} {\tt [} {\tacexpr} {\tt ]} -\end{quote} -{\ident} must denote a context variable bound by a {\tt context} -pattern of a {\tt match} expression. This expression evaluates -replaces the hole of the value of {\ident} by the value of -{\tacexpr}. - -\ErrMsg \errindex{not a context variable} - - -\subsubsection[Generating fresh hypothesis names]{Generating fresh hypothesis names\index{Ltac!fresh@\texttt{fresh}} -\index{fresh@\texttt{fresh}!in Ltac}} - -Tactics sometimes have to generate new names for hypothesis. Letting -the system decide a name with the {\tt intro} tactic is not so good -since it is very awkward to retrieve the name the system gave. -The following expression returns an identifier: -\begin{quote} -{\tt fresh} \nelist{\textrm{\textsl{component}}}{} -\end{quote} -It evaluates to an identifier unbound in the goal. This fresh -identifier is obtained by concatenating the value of the -\textrm{\textsl{component}}'s (each of them is, either an {\qualid} which -has to refer to a (unqualified) name, or directly a name denoted by a -{\qstring}). If the resulting name is already used, it is padded -with a number so that it becomes fresh. If no component is -given, the name is a fresh derivative of the name {\tt H}. - -\subsubsection[Computing in a constr]{Computing in a constr\index{Ltac!eval@\texttt{eval}} -\index{eval@\texttt{eval}!in Ltac}} - -Evaluation of a term can be performed with: -\begin{quote} -{\tt eval} {\nterm{redexpr}} {\tt in} {\term} -\end{quote} -where \nterm{redexpr} is a reduction tactic among {\tt red}, {\tt -hnf}, {\tt compute}, {\tt simpl}, {\tt cbv}, {\tt lazy}, {\tt unfold}, -{\tt fold}, {\tt pattern}. - -\subsubsection{Recovering the type of a term} -%\tacindex{type of} -\index{Ltac!type of@\texttt{type of}} -\index{type of@\texttt{type of}!in Ltac} - -The following returns the type of {\term}: - -\begin{quote} -{\tt type of} {\term} -\end{quote} - -\subsubsection[Manipulating untyped terms]{Manipulating untyped terms\index{Ltac!uconstr@\texttt{uconstr}} -\index{uconstr@\texttt{uconstr}!in Ltac} -\index{Ltac!type\_term@\texttt{type\_term}} -\index{type\_term@\texttt{type\_term}!in Ltac}} - -The terms built in Ltac are well-typed by default. It may not be -appropriate for building large terms using a recursive Ltac function: -the term has to be entirely type checked at each step, resulting in -potentially very slow behavior. It is possible to build untyped terms -using Ltac with the syntax - -\begin{quote} -{\tt uconstr :} {\term} -\end{quote} - -An untyped term, in Ltac, can contain references to hypotheses or to -Ltac variables containing typed or untyped terms. An untyped term can -be type-checked using the function {\tt type\_term} whose argument is -parsed as an untyped term and returns a well-typed term which can be -used in tactics. - -\begin{quote} -{\tt type\_term} {\term} -\end{quote} - -Untyped terms built using {\tt uconstr :} can also be used as -arguments to the {\tt refine} tactic~\ref{refine}. In that case the -untyped term is type checked against the conclusion of the goal, and -the holes which are not solved by the typing procedure are turned into -new subgoals. - -\subsubsection[Counting the goals]{Counting the goals\index{Ltac!numgoals@\texttt{numgoals}}\index{numgoals@\texttt{numgoals}!in Ltac}} - -The number of goals under focus can be recovered using the {\tt - numgoals} function. Combined with the {\tt guard} command below, it -can be used to branch over the number of goals produced by previous tactics. - -\begin{coq_example*} -Ltac pr_numgoals := let n := numgoals in idtac "There are" n "goals". - -Goal True /\ True /\ True. -split;[|split]. -\end{coq_example*} -\begin{coq_example} -all:pr_numgoals. -\end{coq_example} - -\subsubsection[Testing boolean expressions]{Testing boolean expressions\index{Ltac!guard@\texttt{guard}}\index{guard@\texttt{guard}!in Ltac}} - -The {\tt guard} tactic tests a boolean expression, and fails if the expression evaluates to false. If the expression evaluates to true, it succeeds without affecting the proof. - -\begin{quote} -{\tt guard} {\it test} -\end{quote} - -The accepted tests are simple integer comparisons. - -\begin{coq_example*} -Goal True /\ True /\ True. -split;[|split]. -\end{coq_example*} -\begin{coq_example} -all:let n:= numgoals in guard n<4. -Fail all:let n:= numgoals in guard n=2. -\end{coq_example} -\begin{ErrMsgs} - -\item \errindex{Condition not satisfied} - -\end{ErrMsgs} - -\begin{coq_eval} -Reset Initial. -\end{coq_eval} - -\subsubsection[Proving a subgoal as a separate lemma]{Proving a subgoal as a separate lemma\tacindex{abstract}\tacindex{transparent\_abstract} -\index{Tacticals!abstract@{\tt abstract}}\index{Tacticals!transparent\_abstract@{\tt transparent\_abstract}}} - -From the outside ``\texttt{abstract \tacexpr}'' is the same as -{\tt solve \tacexpr}. Internally it saves an auxiliary lemma called -{\ident}\texttt{\_subproof}\textit{n} where {\ident} is the name of the -current goal and \textit{n} is chosen so that this is a fresh name. -Such an auxiliary lemma is inlined in the final proof term. - -This tactical is useful with tactics such as \texttt{omega} or -\texttt{discriminate} that generate huge proof terms. With that tool -the user can avoid the explosion at time of the \texttt{Save} command -without having to cut manually the proof in smaller lemmas. - -It may be useful to generate lemmas minimal w.r.t. the assumptions they depend -on. This can be obtained thanks to the option below. - -\begin{Variants} -\item \texttt{abstract {\tacexpr} using {\ident}}.\\ - Give explicitly the name of the auxiliary lemma. - Use this feature at your own risk; explicitly named and reused subterms - don't play well with asynchronous proofs. -\item \texttt{transparent\_abstract {\tacexpr}}.\\ - Save the subproof in a transparent lemma rather than an opaque one. - Use this feature at your own risk; building computationally relevant terms - with tactics is fragile. -\item \texttt{transparent\_abstract {\tacexpr} using {\ident}}.\\ - Give explicitly the name of the auxiliary transparent lemma. - Use this feature at your own risk; building computationally relevant terms - with tactics is fragile, and explicitly named and reused subterms - don't play well with asynchronous proofs. -\end{Variants} - -\ErrMsg \errindex{Proof is not complete} - -\section[Tactic toplevel definitions]{Tactic toplevel definitions\comindex{Ltac}} - -\subsection{Defining {\ltac} functions} - -Basically, {\ltac} toplevel definitions are made as follows: -%{\tt Tactic Definition} {\ident} {\tt :=} {\tacexpr}\\ -% -%{\tacexpr} is evaluated to $v$ and $v$ is associated to {\ident}. Next, every -%script is evaluated by substituting $v$ to {\ident}. -% -%We can define functional definitions by:\\ -\begin{quote} -{\tt Ltac} {\ident} {\ident}$_1$ ... {\ident}$_n$ {\tt :=} -{\tacexpr} -\end{quote} -This defines a new {\ltac} function that can be used in any tactic -script or new {\ltac} toplevel definition. - -\Rem The preceding definition can equivalently be written: -\begin{quote} -{\tt Ltac} {\ident} {\tt := fun} {\ident}$_1$ ... {\ident}$_n$ -{\tt =>} {\tacexpr} -\end{quote} -Recursive and mutual recursive function definitions are also -possible with the syntax: -\begin{quote} -{\tt Ltac} {\ident}$_1$ {\ident}$_{1,1}$ ... -{\ident}$_{1,m_1}$~~{\tt :=} {\tacexpr}$_1$\\ -{\tt with} {\ident}$_2$ {\ident}$_{2,1}$ ... {\ident}$_{2,m_2}$~~{\tt :=} -{\tacexpr}$_2$\\ -...\\ -{\tt with} {\ident}$_n$ {\ident}$_{n,1}$ ... {\ident}$_{n,m_n}$~~{\tt :=} -{\tacexpr}$_n$ -\end{quote} -\medskip -It is also possible to \emph{redefine} an existing user-defined tactic -using the syntax: -\begin{quote} -{\tt Ltac} {\qualid} {\ident}$_1$ ... {\ident}$_n$ {\tt ::=} -{\tacexpr} -\end{quote} -A previous definition of {\qualid} must exist in the environment. -The new definition will always be used instead of the old one and -it goes across module boundaries. - -If preceded by the keyword {\tt Local} the tactic definition will not -be exported outside the current module. - -\subsection[Printing {\ltac} tactics]{Printing {\ltac} tactics\comindex{Print Ltac}} - -Defined {\ltac} functions can be displayed using the command - -\begin{quote} -{\tt Print Ltac {\qualid}.} -\end{quote} - -The command {\tt Print Ltac Signatures\comindex{Print Ltac Signatures}} displays a list of all user-defined tactics, with their arguments. - -\section{Debugging {\ltac} tactics} - -\subsection[Info trace]{Info trace\comindex{Info}\optindex{Info Level}} - -It is possible to print the trace of the path eventually taken by an {\ltac} script. That is, the list of executed tactics, discarding all the branches which have failed. To that end the {\tt Info} command can be used with the following syntax. - -\begin{quote} -{\tt Info} {\num} {\tacexpr}. -\end{quote} - -The number {\num} is the unfolding level of tactics in the trace. At level $0$, the trace contains a sequence of tactics in the actual script, at level $1$, the trace will be the concatenation of the traces of these tactics, etc\ldots - -\begin{coq_eval} -Reset Initial. -\end{coq_eval} -\begin{coq_example*} -Ltac t x := exists x; reflexivity. - -Goal exists n, n=0. -\end{coq_example*} -\begin{coq_example} -Info 0 t 1||t 0. -\end{coq_example} -\begin{coq_example*} -Undo. -\end{coq_example*} -\begin{coq_example} -Info 1 t 1||t 0. -\end{coq_example} - -The trace produced by {\tt Info} tries its best to be a reparsable {\ltac} script, but this goal is not achievable in all generality. So some of the output traces will contain oddities. - -As an additional help for debugging, the trace produced by {\tt Info} contains (in comments) the messages produced by the {\tt idtac} tacticals~\ref{ltac:idtac} at the right possition in the script. In particular, the calls to {\tt idtac} in branches which failed are not printed. - -An alternative to the {\tt Info} command is to use the {\tt Info Level} option as follows: - -\begin{quote} -{\tt Set Info Level} \num. -\end{quote} - -This will automatically print the same trace as {\tt Info \num} at each tactic call. The unfolding level can be overridden by a call to the {\tt Info} command. And this option can be turned off with: - -\begin{quote} -{\tt Unset Info Level} \num. -\end{quote} - -The current value for the {\tt Info Level} option can be checked using the {\tt Test Info Level} command. - -\subsection[Interactive debugger]{Interactive debugger\optindex{Ltac Debug}\optindex{Ltac Batch Debug}} - -The {\ltac} interpreter comes with a step-by-step debugger. The -debugger can be activated using the command - -\begin{quote} -{\tt Set Ltac Debug.} -\end{quote} - -\noindent and deactivated using the command - -\begin{quote} -{\tt Unset Ltac Debug.} -\end{quote} - -To know if the debugger is on, use the command \texttt{Test Ltac Debug}. -When the debugger is activated, it stops at every step of the -evaluation of the current {\ltac} expression and it prints information -on what it is doing. The debugger stops, prompting for a command which -can be one of the following: - -\medskip -\begin{tabular}{ll} -simple newline: & go to the next step\\ -h: & get help\\ -x: & exit current evaluation\\ -s: & continue current evaluation without stopping\\ -r $n$: & advance $n$ steps further\\ -r {\qstring}: & advance up to the next call to ``{\tt idtac} {\qstring}''\\ -\end{tabular} - -A non-interactive mode for the debugger is available via the command - -\begin{quote} -{\tt Set Ltac Batch Debug.} -\end{quote} - -This option has the effect of presenting a newline at every prompt, -when the debugger is on. The debug log thus created, which does not -require user input to generate when this option is set, can then be -run through external tools such as \texttt{diff}. - -\subsection[Profiling {\ltac} tactics]{Profiling {\ltac} tactics\optindex{Ltac Profiling}\comindex{Show Ltac Profile}\comindex{Reset Ltac Profile}} - -It is possible to measure the time spent in invocations of primitive tactics as well as tactics defined in {\ltac} and their inner invocations. The primary use is the development of complex tactics, which can sometimes be so slow as to impede interactive usage. The reasons for the performence degradation can be intricate, like a slowly performing {\ltac} match or a sub-tactic whose performance only degrades in certain situations. The profiler generates a call tree and indicates the time spent in a tactic depending its calling context. Thus it allows to locate the part of a tactic definition that contains the performance bug. - -\begin{quote} -{\tt Set Ltac Profiling}. -\end{quote} -Enables the profiler - -\begin{quote} -{\tt Unset Ltac Profiling}. -\end{quote} -Disables the profiler - -\begin{quote} -{\tt Show Ltac Profile}. -\end{quote} -Prints the profile - -\begin{quote} -{\tt Show Ltac Profile} {\qstring}. -\end{quote} -Prints a profile for all tactics that start with {\qstring}. Append a period (.) to the string if you only want exactly that name. - -\begin{quote} -{\tt Reset Ltac Profile}. -\end{quote} -Resets the profile, that is, deletes all accumulated information. Note that backtracking across a {\tt Reset Ltac Profile} will not restore the information. - -\begin{coq_eval} -Reset Initial. -\end{coq_eval} -\begin{coq_example*} -Require Import Coq.omega.Omega. - -Ltac mytauto := tauto. -Ltac tac := intros; repeat split; omega || mytauto. - -Notation max x y := (x + (y - x)) (only parsing). -\end{coq_example*} -\begin{coq_example*} -Goal forall x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z, - max x (max y z) = max (max x y) z /\ max x (max y z) = max (max x y) z - /\ (A /\ B /\ C /\ D /\ E /\ F /\ G /\ H /\ I /\ J /\ K /\ L /\ M /\ N /\ O /\ P /\ Q /\ R /\ S /\ T /\ U /\ V /\ W /\ X /\ Y /\ Z - -> Z /\ Y /\ X /\ W /\ V /\ U /\ T /\ S /\ R /\ Q /\ P /\ O /\ N /\ M /\ L /\ K /\ J /\ I /\ H /\ G /\ F /\ E /\ D /\ C /\ B /\ A). -Proof. -\end{coq_example*} -\begin{coq_example} - Set Ltac Profiling. - tac. -\end{coq_example} -{\let\textit\texttt% use tt mode for the output of ltacprof -\begin{coq_example} - Show Ltac Profile. -\end{coq_example} -\begin{coq_example} - Show Ltac Profile "omega". -\end{coq_example} -} -\begin{coq_example*} -Abort. -Unset Ltac Profiling. -\end{coq_example*} - -\tacindex{start ltac profiling}\tacindex{stop ltac profiling} -The following two tactics behave like {\tt idtac} but enable and disable the profiling. They allow you to exclude parts of a proof script from profiling. - -\begin{quote} -{\tt start ltac profiling}. -\end{quote} - -\begin{quote} -{\tt stop ltac profiling}. -\end{quote} - -\tacindex{reset ltac profile}\tacindex{show ltac profile} -The following tactics behave like the corresponding vernacular commands and allow displaying and resetting the profile from tactic scripts for benchmarking purposes. - -\begin{quote} -{\tt reset ltac profile}. -\end{quote} - -\begin{quote} -{\tt show ltac profile}. -\end{quote} - -\begin{quote} -{\tt show ltac profile} {\qstring}. -\end{quote} - -You can also pass the {\tt -profile-ltac} command line option to {\tt coqc}, which performs a {\tt Set Ltac Profiling} at the beginning of each document, and a {\tt Show Ltac Profile} at the end. - -Note that the profiler currently does not handle backtracking into multi-success tactics, and issues a warning to this effect in many cases when such backtracking occurs. - -\subsection[Run-time optimization tactic]{Run-time optimization tactic\label{tactic-optimizeheap}}. - -The following tactic behaves like {\tt idtac}, and running it compacts the heap in the -OCaml run-time system. It is analogous to the Vernacular command {\tt Optimize Heap} (see~\ref{vernac-optimizeheap}). - -\tacindex{optimize\_heap} -\begin{quote} -{\tt optimize\_heap}. -\end{quote} - -\endinput - -\subsection{Permutation on closed lists} - -\begin{figure}[b] -\begin{center} -\fbox{\begin{minipage}{0.95\textwidth} -\begin{coq_eval} -Reset Initial. -\end{coq_eval} -\begin{coq_example*} -Require Import List. -Section Sort. -Variable A : Set. -Inductive permut : list A -> list A -> Prop := - | permut_refl : forall l, permut l l - | permut_cons : - forall a l0 l1, permut l0 l1 -> permut (a :: l0) (a :: l1) - | permut_append : forall a l, permut (a :: l) (l ++ a :: nil) - | permut_trans : - forall l0 l1 l2, permut l0 l1 -> permut l1 l2 -> permut l0 l2. -End Sort. -\end{coq_example*} -\end{center} -\caption{Definition of the permutation predicate} -\label{permutpred} -\end{figure} - - -Another more complex example is the problem of permutation on closed -lists. The aim is to show that a closed list is a permutation of -another one. First, we define the permutation predicate as shown on -Figure~\ref{permutpred}. - -\begin{figure}[p] -\begin{center} -\fbox{\begin{minipage}{0.95\textwidth} -\begin{coq_example} -Ltac Permut n := - match goal with - | |- (permut _ ?l ?l) => apply permut_refl - | |- (permut _ (?a :: ?l1) (?a :: ?l2)) => - let newn := eval compute in (length l1) in - (apply permut_cons; Permut newn) - | |- (permut ?A (?a :: ?l1) ?l2) => - match eval compute in n with - | 1 => fail - | _ => - let l1' := constr:(l1 ++ a :: nil) in - (apply (permut_trans A (a :: l1) l1' l2); - [ apply permut_append | compute; Permut (pred n) ]) - end - end. -Ltac PermutProve := - match goal with - | |- (permut _ ?l1 ?l2) => - match eval compute in (length l1 = length l2) with - | (?n = ?n) => Permut n - end - end. -\end{coq_example} -\end{minipage}} -\end{center} -\caption{Permutation tactic} -\label{permutltac} -\end{figure} - -\begin{figure}[p] -\begin{center} -\fbox{\begin{minipage}{0.95\textwidth} -\begin{coq_example*} -Lemma permut_ex1 : - permut nat (1 :: 2 :: 3 :: nil) (3 :: 2 :: 1 :: nil). -Proof. -PermutProve. -Qed. - -Lemma permut_ex2 : - permut nat - (0 :: 1 :: 2 :: 3 :: 4 :: 5 :: 6 :: 7 :: 8 :: 9 :: nil) - (0 :: 2 :: 4 :: 6 :: 8 :: 9 :: 7 :: 5 :: 3 :: 1 :: nil). -Proof. -PermutProve. -Qed. -\end{coq_example*} -\end{minipage}} -\end{center} -\caption{Examples of {\tt PermutProve} use} -\label{permutlem} -\end{figure} - -Next, we can write naturally the tactic and the result can be seen on -Figure~\ref{permutltac}. We can notice that we use two toplevel -definitions {\tt PermutProve} and {\tt Permut}. The function to be -called is {\tt PermutProve} which computes the lengths of the two -lists and calls {\tt Permut} with the length if the two lists have the -same length. {\tt Permut} works as expected. If the two lists are -equal, it concludes. Otherwise, if the lists have identical first -elements, it applies {\tt Permut} on the tail of the lists. Finally, -if the lists have different first elements, it puts the first element -of one of the lists (here the second one which appears in the {\tt - permut} predicate) at the end if that is possible, i.e., if the new -first element has been at this place previously. To verify that all -rotations have been done for a list, we use the length of the list as -an argument for {\tt Permut} and this length is decremented for each -rotation down to, but not including, 1 because for a list of length -$n$, we can make exactly $n-1$ rotations to generate at most $n$ -distinct lists. Here, it must be noticed that we use the natural -numbers of {\Coq} for the rotation counter. On Figure~\ref{ltac}, we -can see that it is possible to use usual natural numbers but they are -only used as arguments for primitive tactics and they cannot be -handled, in particular, we cannot make computations with them. So, a -natural choice is to use {\Coq} data structures so that {\Coq} makes -the computations (reductions) by {\tt eval compute in} and we can get -the terms back by {\tt match}. - -With {\tt PermutProve}, we can now prove lemmas such those shown on -Figure~\ref{permutlem}. - - -\subsection{Deciding intuitionistic propositional logic} - -\begin{figure}[tbp] -\begin{center} -\fbox{\begin{minipage}{0.95\textwidth} -\begin{coq_example} -Ltac Axioms := - match goal with - | |- True => trivial - | _:False |- _ => elimtype False; assumption - | _:?A |- ?A => auto - end. -Ltac DSimplif := - repeat - (intros; - match goal with - | id:(~ _) |- _ => red in id - | id:(_ /\ _) |- _ => - elim id; do 2 intro; clear id - | id:(_ \/ _) |- _ => - elim id; intro; clear id - | id:(?A /\ ?B -> ?C) |- _ => - cut (A -> B -> C); - [ intro | intros; apply id; split; assumption ] - | id:(?A \/ ?B -> ?C) |- _ => - cut (B -> C); - [ cut (A -> C); - [ intros; clear id - | intro; apply id; left; assumption ] - | intro; apply id; right; assumption ] - | id0:(?A -> ?B),id1:?A |- _ => - cut B; [ intro; clear id0 | apply id0; assumption ] - | |- (_ /\ _) => split - | |- (~ _) => red - end). -\end{coq_example} -\end{minipage}} -\end{center} -\caption{Deciding intuitionistic propositions (1)} -\label{tautoltaca} -\end{figure} - -\begin{figure} -\begin{center} -\fbox{\begin{minipage}{0.95\textwidth} -\begin{coq_example} -Ltac TautoProp := - DSimplif; - Axioms || - match goal with - | id:((?A -> ?B) -> ?C) |- _ => - cut (B -> C); - [ intro; cut (A -> B); - [ intro; cut C; - [ intro; clear id | apply id; assumption ] - | clear id ] - | intro; apply id; intro; assumption ]; TautoProp - | id:(~ ?A -> ?B) |- _ => - cut (False -> B); - [ intro; cut (A -> False); - [ intro; cut B; - [ intro; clear id | apply id; assumption ] - | clear id ] - | intro; apply id; red; intro; assumption ]; TautoProp - | |- (_ \/ _) => (left; TautoProp) || (right; TautoProp) - end. -\end{coq_example} -\end{minipage}} -\end{center} -\caption{Deciding intuitionistic propositions (2)} -\label{tautoltacb} -\end{figure} - -The pattern matching on goals allows a complete and so a powerful -backtracking when returning tactic values. An interesting application -is the problem of deciding intuitionistic propositional logic. -Considering the contraction-free sequent calculi {\tt LJT*} of -Roy~Dyckhoff (\cite{Dyc92}), it is quite natural to code such a tactic -using the tactic language. On Figure~\ref{tautoltaca}, the tactic {\tt - Axioms} tries to conclude using usual axioms. The {\tt DSimplif} -tactic applies all the reversible rules of Dyckhoff's system. -Finally, on Figure~\ref{tautoltacb}, the {\tt TautoProp} tactic (the -main tactic to be called) simplifies with {\tt DSimplif}, tries to -conclude with {\tt Axioms} and tries several paths using the -backtracking rules (one of the four Dyckhoff's rules for the left -implication to get rid of the contraction and the right or). - -\begin{figure}[tb] -\begin{center} -\fbox{\begin{minipage}{0.95\textwidth} -\begin{coq_example*} -Lemma tauto_ex1 : forall A B:Prop, A /\ B -> A \/ B. -Proof. -TautoProp. -Qed. - -Lemma tauto_ex2 : - forall A B:Prop, (~ ~ B -> B) -> (A -> B) -> ~ ~ A -> B. -Proof. -TautoProp. -Qed. -\end{coq_example*} -\end{minipage}} -\end{center} -\caption{Proofs of tautologies with {\tt TautoProp}} -\label{tautolem} -\end{figure} - -For example, with {\tt TautoProp}, we can prove tautologies like those of -Figure~\ref{tautolem}. - - -\subsection{Deciding type isomorphisms} - -A more tricky problem is to decide equalities between types and modulo -isomorphisms. Here, we choose to use the isomorphisms of the simply typed -$\lb{}$-calculus with Cartesian product and $unit$ type (see, for example, -\cite{RC95}). The axioms of this $\lb{}$-calculus are given by -Figure~\ref{isosax}. - -\begin{figure} -\begin{center} -\fbox{\begin{minipage}{0.95\textwidth} -\begin{coq_eval} -Reset Initial. -\end{coq_eval} -\begin{coq_example*} -Open Scope type_scope. -Section Iso_axioms. -Variables A B C : Set. -Axiom Com : A * B = B * A. -Axiom Ass : A * (B * C) = A * B * C. -Axiom Cur : (A * B -> C) = (A -> B -> C). -Axiom Dis : (A -> B * C) = (A -> B) * (A -> C). -Axiom P_unit : A * unit = A. -Axiom AR_unit : (A -> unit) = unit. -Axiom AL_unit : (unit -> A) = A. -Lemma Cons : B = C -> A * B = A * C. -Proof. -intro Heq; rewrite Heq; reflexivity. -Qed. -End Iso_axioms. -\end{coq_example*} -\end{minipage}} -\end{center} -\caption{Type isomorphism axioms} -\label{isosax} -\end{figure} - -The tactic to judge equalities modulo this axiomatization can be written as -shown on Figures~\ref{isosltac1} and~\ref{isosltac2}. The algorithm is quite -simple. Types are reduced using axioms that can be oriented (this done by {\tt -MainSimplif}). The normal forms are sequences of Cartesian -products without Cartesian product in the left component. These normal forms -are then compared modulo permutation of the components (this is done by {\tt -CompareStruct}). The main tactic to be called and realizing this algorithm is -{\tt IsoProve}. - -\begin{figure} -\begin{center} -\fbox{\begin{minipage}{0.95\textwidth} -\begin{coq_example} -Ltac DSimplif trm := - match trm with - | (?A * ?B * ?C) => - rewrite <- (Ass A B C); try MainSimplif - | (?A * ?B -> ?C) => - rewrite (Cur A B C); try MainSimplif - | (?A -> ?B * ?C) => - rewrite (Dis A B C); try MainSimplif - | (?A * unit) => - rewrite (P_unit A); try MainSimplif - | (unit * ?B) => - rewrite (Com unit B); try MainSimplif - | (?A -> unit) => - rewrite (AR_unit A); try MainSimplif - | (unit -> ?B) => - rewrite (AL_unit B); try MainSimplif - | (?A * ?B) => - (DSimplif A; try MainSimplif) || (DSimplif B; try MainSimplif) - | (?A -> ?B) => - (DSimplif A; try MainSimplif) || (DSimplif B; try MainSimplif) - end - with MainSimplif := - match goal with - | |- (?A = ?B) => try DSimplif A; try DSimplif B - end. -Ltac Length trm := - match trm with - | (_ * ?B) => let succ := Length B in constr:(S succ) - | _ => constr:1 - end. -Ltac assoc := repeat rewrite <- Ass. -\end{coq_example} -\end{minipage}} -\end{center} -\caption{Type isomorphism tactic (1)} -\label{isosltac1} -\end{figure} - -\begin{figure} -\begin{center} -\fbox{\begin{minipage}{0.95\textwidth} -\begin{coq_example} -Ltac DoCompare n := - match goal with - | [ |- (?A = ?A) ] => reflexivity - | [ |- (?A * ?B = ?A * ?C) ] => - apply Cons; let newn := Length B in DoCompare newn - | [ |- (?A * ?B = ?C) ] => - match eval compute in n with - | 1 => fail - | _ => - pattern (A * B) at 1; rewrite Com; assoc; DoCompare (pred n) - end - end. -Ltac CompareStruct := - match goal with - | [ |- (?A = ?B) ] => - let l1 := Length A - with l2 := Length B in - match eval compute in (l1 = l2) with - | (?n = ?n) => DoCompare n - end - end. -Ltac IsoProve := MainSimplif; CompareStruct. -\end{coq_example} -\end{minipage}} -\end{center} -\caption{Type isomorphism tactic (2)} -\label{isosltac2} -\end{figure} - -Figure~\ref{isoslem} gives examples of what can be solved by {\tt IsoProve}. - -\begin{figure} -\begin{center} -\fbox{\begin{minipage}{0.95\textwidth} -\begin{coq_example*} -Lemma isos_ex1 : - forall A B:Set, A * unit * B = B * (unit * A). -Proof. -intros; IsoProve. -Qed. - -Lemma isos_ex2 : - forall A B C:Set, - (A * unit -> B * (C * unit)) = - (A * unit -> (C -> unit) * C) * (unit -> A -> B). -Proof. -intros; IsoProve. -Qed. -\end{coq_example*} -\end{minipage}} -\end{center} -\caption{Type equalities solved by {\tt IsoProve}} -\label{isoslem} -\end{figure} - -%%% Local Variables: -%%% mode: latex -%%% TeX-master: "Reference-Manual" -%%% End: diff --git a/doc/refman/Reference-Manual.tex b/doc/refman/Reference-Manual.tex index d373f76bf..ba4018d77 100644 --- a/doc/refman/Reference-Manual.tex +++ b/doc/refman/Reference-Manual.tex @@ -94,7 +94,6 @@ Options A and B of the licence are {\em not} elected.} %BEGIN LATEX \defaultheaders %END LATEX -\include{RefMan-gal.v}% Gallina \part{The proof engine} diff --git a/doc/sphinx/_static/CoqNotations.ttf b/doc/sphinx/_static/CoqNotations.ttf Binary files differnew file mode 100644 index 000000000..da8f2850d --- /dev/null +++ b/doc/sphinx/_static/CoqNotations.ttf diff --git a/doc/sphinx/_static/UbuntuMono-Square.ttf b/doc/sphinx/_static/UbuntuMono-Square.ttf Binary files differdeleted file mode 100644 index 12b7c6d51..000000000 --- a/doc/sphinx/_static/UbuntuMono-Square.ttf +++ /dev/null diff --git a/doc/sphinx/_static/notations.css b/doc/sphinx/_static/notations.css index 9b7b826d5..f899945a3 100644 --- a/doc/sphinx/_static/notations.css +++ b/doc/sphinx/_static/notations.css @@ -22,10 +22,10 @@ } @font-face { /* This font has been edited to center all characters */ - font-family: 'UbuntuMono-Square'; + font-family: 'CoqNotations'; font-style: normal; font-weight: 800; - src: local('UbuntuMono-Square'), url(./UbuntuMono-Square.ttf) format('truetype'); + src: local('CoqNotations'), url(./CoqNotations.ttf) format('truetype'); } .notation .notation-sup, .notation .notation-sub { @@ -34,15 +34,15 @@ color: black; /* cursor: help; */ display: inline-block; - font-size: 0.5em; + font-size: 0.45em; font-weight: bolder; - font-family: UbuntuMono-Square, monospace; - height: 2em; + font-family: CoqNotations, monospace; + height: 2.2em; line-height: 1.6em; position: absolute; right: -1em; /* half of the width */ text-align: center; - width: 2em; + width: 2.2em; } .notation .repeat { diff --git a/doc/sphinx/addendum/extended-pattern-matching.rst b/doc/sphinx/addendum/extended-pattern-matching.rst index 64d4eddf0..1d3b66173 100644 --- a/doc/sphinx/addendum/extended-pattern-matching.rst +++ b/doc/sphinx/addendum/extended-pattern-matching.rst @@ -305,6 +305,8 @@ explicitations (as for terms 2.7.11). end). +.. _matching-dependent: + Matching objects of dependent types ----------------------------------- @@ -414,6 +416,7 @@ length, by writing I have a copy of :g:`b` in type :g:`listn 0` resp :g:`listn (S n')`. +.. _match-in-patterns: Patterns in ``in`` ~~~~~~~~~~~~~~~~~~ diff --git a/doc/sphinx/addendum/extraction.rst b/doc/sphinx/addendum/extraction.rst index d7f97edab..38365e403 100644 --- a/doc/sphinx/addendum/extraction.rst +++ b/doc/sphinx/addendum/extraction.rst @@ -1,16 +1,16 @@ -.. _extraction: - .. include:: ../replaces.rst -Extraction of programs in OCaml and Haskell -============================================ +.. _extraction: + +Extraction of programs in |OCaml| and Haskell +============================================= :Authors: Jean-Christophe Filliâtre and Pierre Letouzey We present here the |Coq| extraction commands, used to build certified and relatively efficient functional programs, extracting them from either |Coq| functions or |Coq| proofs of specifications. The -functional languages available as output are currently OCaml, Haskell +functional languages available as output are currently |OCaml|, Haskell and Scheme. In the following, "ML" will be used (abusively) to refer to any of the three. @@ -89,11 +89,11 @@ in the |Coq| sources. .. cmd:: Extraction TestCompile @qualid ... @qualid. All the mentioned objects and all their dependencies are extracted - to a temporary OCaml file, just as in ``Extraction "file"``. Then + to a temporary |OCaml| file, just as in ``Extraction "file"``. Then this temporary file and its signature are compiled with the same - OCaml compiler used to built |Coq|. This command succeeds only - if the extraction and the OCaml compilation succeed. It fails - if the current target language of the extraction is not OCaml. + |OCaml| compiler used to built |Coq|. This command succeeds only + if the extraction and the |OCaml| compilation succeed. It fails + if the current target language of the extraction is not |OCaml|. Extraction Options ------------------- @@ -102,26 +102,26 @@ Setting the target language ~~~~~~~~~~~~~~~~~~~~~~~~~~~ The ability to fix target language is the first and more important -of the extraction options. Default is ``Ocaml``. +of the extraction options. Default is ``OCaml``. -.. cmd:: Extraction Language Ocaml. +.. cmd:: Extraction Language OCaml. .. cmd:: Extraction Language Haskell. .. cmd:: Extraction Language Scheme. Inlining and optimizations ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Since OCaml is a strict language, the extracted code has to +Since |OCaml| is a strict language, the extracted code has to be optimized in order to be efficient (for instance, when using induction principles we do not want to compute all the recursive calls but only the needed ones). So the extraction mechanism provides an automatic optimization routine that will be called each time the user -want to generate OCaml programs. The optimizations can be split in two +want to generate |OCaml| programs. The optimizations can be split in two groups: the type-preserving ones (essentially constant inlining and reductions) and the non type-preserving ones (some function abstractions of dummy types are removed when it is deemed safe in order to have more elegant types). Therefore some constants may not appear in the -resulting monolithic OCaml program. In the case of modular extraction, +resulting monolithic |OCaml| program. In the case of modular extraction, even if some inlining is done, the inlined constant are nevertheless printed, to ensure session-independent programs. @@ -264,10 +264,9 @@ what ML term corresponds to a given axiom. be inlined everywhere instead of being declared via a ``let``. .. note:: - - This command is sugar for an ``Extract Constant`` followed - by a ``Extraction Inline``. Hence a ``Reset Extraction Inline`` - will have an effect on the realized and inlined axiom. + This command is sugar for an ``Extract Constant`` followed + by a ``Extraction Inline``. Hence a ``Reset Extraction Inline`` + will have an effect on the realized and inlined axiom. .. caution:: It is the responsibility of the user to ensure that the ML terms given to realize the axioms do have the expected types. In @@ -336,7 +335,7 @@ native boolean type instead of |Coq| one. The syntax is the following: argument is considered to have one unit argument, in order to block early evaluation of the branch: ``| O => bar`` leads to the functional form ``(fun () -> bar)``. For instance, when extracting ``nat`` - into OCaml ``int``, the code to provide has type: + into |OCaml| ``int``, the code to provide has type: ``(unit->'a)->(int->'a)->int->'a``. .. caution:: As for ``Extract Constant``, this command should be used with care: @@ -347,15 +346,15 @@ native boolean type instead of |Coq| one. The syntax is the following: * Extracting an inductive type to a pre-existing ML inductive type is quite sound. But extracting to a general type (by providing an ad-hoc pattern-matching) will often **not** be fully rigorously - correct. For instance, when extracting ``nat`` to OCaml ``int``, + correct. For instance, when extracting ``nat`` to |OCaml| ``int``, it is theoretically possible to build ``nat`` values that are - larger than OCaml ``max_int``. It is the user's responsibility to + larger than |OCaml| ``max_int``. It is the user's responsibility to be sure that no overflow or other bad events occur in practice. * Translating an inductive type to an arbitrary ML type does **not** magically improve the asymptotic complexity of functions, even if the ML type is an efficient representation. For instance, when extracting - ``nat`` to OCaml ``int``, the function ``Nat.mul`` stays quadratic. + ``nat`` to |OCaml| ``int``, the function ``Nat.mul`` stays quadratic. It might be interesting to associate this translation with some specific ``Extract Constant`` when primitive counterparts exist. @@ -369,9 +368,9 @@ Typical examples are the following: .. note:: - When extracting to Ocaml, if an inductive constructor or type has arity 2 and + When extracting to |OCaml|, if an inductive constructor or type has arity 2 and the corresponding string is enclosed by parentheses, and the string meets - Ocaml's lexical criteria for an infix symbol, then the rest of the string is + |OCaml|'s lexical criteria for an infix symbol, then the rest of the string is used as infix constructor or type. .. coqtop:: in @@ -380,7 +379,7 @@ Typical examples are the following: Extract Inductive prod => "(*)" [ "(,)" ]. As an example of translation to a non-inductive datatype, let's turn -``nat`` into OCaml ``int`` (see caveat above): +``nat`` into |OCaml| ``int`` (see caveat above): .. coqtop:: in @@ -394,7 +393,7 @@ directly depends from the names of the |Coq| files. It may happen that these filenames are in conflict with already existing files, either in the standard library of the target language or in other code that is meant to be linked with the extracted code. -For instance the module ``List`` exists both in |Coq| and in OCaml. +For instance the module ``List`` exists both in |Coq| and in |OCaml|. It is possible to instruct the extraction not to use particular filenames. .. cmd:: Extraction Blacklist @ident ... @ident. @@ -410,7 +409,7 @@ It is possible to instruct the extraction not to use particular filenames. Allow the extraction to use any filename. -For OCaml, a typical use of these commands is +For |OCaml|, a typical use of these commands is ``Extraction Blacklist String List``. Differences between |Coq| and ML type systems @@ -418,7 +417,7 @@ Differences between |Coq| and ML type systems Due to differences between |Coq| and ML type systems, some extracted programs are not directly typable in ML. -We now solve this problem (at least in OCaml) by adding +We now solve this problem (at least in |OCaml|) by adding when needed some unsafe casting ``Obj.magic``, which give a generic type ``'a`` to any term. @@ -432,7 +431,7 @@ function: Definition dp {A B:Type}(x:A)(y:B)(f:forall C:Type, C->C) := (f A x, f B y). -In Ocaml, for instance, the direct extracted term would be:: +In |OCaml|, for instance, the direct extracted term would be:: let dp x y f = Pair((f () x),(f () y)) @@ -455,12 +454,12 @@ of a constructor; for example: Inductive anything : Type := dummy : forall A:Set, A -> anything. which corresponds to the definition of an ML dynamic type. -In OCaml, we must cast any argument of the constructor dummy +In |OCaml|, we must cast any argument of the constructor dummy (no GADT are produced yet by the extraction). Even with those unsafe castings, you should never get error like ``segmentation fault``. In fact even if your program may seem -ill-typed to the Ocaml type-checker, it can't go wrong : it comes +ill-typed to the |OCaml| type-checker, it can't go wrong : it comes from a Coq well-typed terms, so for example inductive types will always have the correct number of arguments, etc. Of course, when launching manually some extracted function, you should apply it to arguments @@ -470,14 +469,14 @@ More details about the correctness of the extracted programs can be found in :cite:`Let02`. We have to say, though, that in most "realistic" programs, these problems do not -occur. For example all the programs of Coq library are accepted by the OCaml +occur. For example all the programs of Coq library are accepted by the |OCaml| type-checker without any ``Obj.magic`` (see examples below). Some examples ------------- We present here two examples of extractions, taken from the -|Coq| Standard Library. We choose OCaml as target language, +|Coq| Standard Library. We choose |OCaml| as target language, but all can be done in the other dialects with slight modifications. We then indicate where to find other examples and tests of extraction. @@ -493,7 +492,7 @@ This module contains a theorem ``eucl_dev``, whose type is:: where ``diveucl`` is a type for the pair of the quotient and the modulo, plus some logical assertions that disappear during extraction. -We can now extract this program to OCaml: +We can now extract this program to |OCaml|: .. coqtop:: none @@ -513,7 +512,7 @@ You can then copy-paste the output to a file ``euclid.ml`` or let Extraction "euclid" eucl_dev. -Let us play the resulting program (in an OCaml toplevel):: +Let us play the resulting program (in an |OCaml| toplevel):: #use "euclid.ml";; type nat = O | S of nat @@ -527,7 +526,7 @@ Let us play the resulting program (in an OCaml toplevel):: # eucl_dev (S (S O)) (S (S (S (S (S O)))));; - : diveucl = Divex (S (S O), S O) -It is easier to test on OCaml integers:: +It is easier to test on |OCaml| integers:: # let rec nat_of_int = function 0 -> O | n -> S (nat_of_int (n-1));; val nat_of_int : int -> nat = <fun> diff --git a/doc/sphinx/addendum/generalized-rewriting.rst b/doc/sphinx/addendum/generalized-rewriting.rst index da9e97e6f..d60387f4f 100644 --- a/doc/sphinx/addendum/generalized-rewriting.rst +++ b/doc/sphinx/addendum/generalized-rewriting.rst @@ -1,14 +1,12 @@ -.. _generalizedrewriting: - ------------------------ - Generalized rewriting ------------------------ +.. include:: ../preamble.rst +.. include:: ../replaces.rst -:Author: Matthieu Sozeau +.. _generalizedrewriting: Generalized rewriting ===================== +:Author: Matthieu Sozeau This chapter presents the extension of several equality related tactics to work over user-defined structures (called setoids) that are @@ -479,7 +477,7 @@ The declaration itself amounts to the definition of an object of the record type ``Coq.Classes.RelationClasses.Equivalence`` and a hint added to the ``typeclass_instances`` hint database. Morphism declarations are also instances of a type class defined in ``Classes.Morphisms``. See the -documentation on type classes :ref:`TODO-chapter-20-type-classes` +documentation on type classes :ref:`typeclasses` and the theories files in Classes for further explanations. One can inform the rewrite tactic about morphisms and relations just @@ -707,22 +705,20 @@ defined constants as transparent by default. This may slow down the resolution due to a lot of unifications (all the declared ``Proper`` instances are tried at each node of the search tree). To speed it up, declare your constant as rigid for proof search using the command -``Typeclasses Opaque`` (see :ref:`TODO-20.6.7-typeclasses-transparency`). - +``Typeclasses Opaque`` (see :ref:`TypeclassesTransparent`). Strategies for rewriting ------------------------ - Definitions ~~~~~~~~~~~ -The generalized rewriting tactic is based on a set of strategies that -can be combined to obtain custom rewriting procedures. Its set of -strategies is based on Elan’s rewriting strategies :ref:`TODO-102-biblio`. Rewriting +The generalized rewriting tactic is based on a set of strategies that can be +combined to obtain custom rewriting procedures. Its set of strategies is based +on Elan’s rewriting strategies :cite:`Luttik97specificationof`. Rewriting strategies are applied using the tactic ``rewrite_strat s`` where ``s`` is a -strategy expression. Strategies are defined inductively as described -by the following grammar: +strategy expression. Strategies are defined inductively as described by the +following grammar: .. productionlist:: rewriting s, t, u : `strategy` @@ -812,7 +808,7 @@ Hint databases created for ``autorewrite`` can also be used by ``rewrite_strat`` using the ``hints`` strategy that applies any of the lemmas at the current subterm. The ``terms`` strategy takes the lemma names directly as arguments. The ``eval`` strategy expects a reduction -expression (see :ref:`TODO-8.7-performing-computations`) and succeeds +expression (see :ref:`performingcomputations`) and succeeds if it reduces the subterm under consideration. The ``fold`` strategy takes a term ``c`` and tries to *unify* it to the current subterm, converting it to ``c`` on success, it is stronger than the tactic ``fold``. diff --git a/doc/sphinx/addendum/implicit-coercions.rst b/doc/sphinx/addendum/implicit-coercions.rst index f5ca5be44..ec1b942e0 100644 --- a/doc/sphinx/addendum/implicit-coercions.rst +++ b/doc/sphinx/addendum/implicit-coercions.rst @@ -1,7 +1,7 @@ -.. _implicitcoercions: - .. include:: ../replaces.rst +.. _implicitcoercions: + Implicit Coercions ==================== @@ -166,7 +166,7 @@ Declaration of Coercions Assumptions can be declared as coercions at declaration time. This extends the grammar of assumptions from -Figure :ref:`TODO-1.3-sentences-syntax` as follows: +Figure :ref:`vernacular` as follows: .. FIXME: @@ -186,7 +186,7 @@ assumptions are declared as coercions. Similarly, constructors of inductive types can be declared as coercions at definition time of the inductive type. This extends and modifies the -grammar of inductive types from Figure :ref:`TODO-1.3-sentences-syntax` as follows: +grammar of inductive types from Figure :ref:`vernacular` as follows: .. FIXME: @@ -267,29 +267,29 @@ Activating the Printing of Coercions To skip the printing of coercion `qualid`, use ``Remove Printing Coercion`` `qualid`. By default, a coercion is never printed. +.. _coercions-classes-as-records: Classes as Records ------------------ -We allow the definition of *Structures with Inheritance* (or -classes as records) by extending the existing ``Record`` macro -(see Section :ref:`TODO-2.1-Record`). Its new syntax is: - -.. cmd:: Record {? >} @ident {? @binders} : @sort := {? @ident} { {+; @ident :{? >} @term } }. - - The first identifier `ident` is the name of the defined record and - `sort` is its type. The optional identifier after ``:=`` is the name - of the constuctor (it will be ``Build_``\ `ident` if not given). - The other identifiers are the names of the fields, and the `term` - are their respective types. If ``:>`` is used instead of ``:`` in - the declaration of a field, then the name of this field is automatically - declared as a coercion from the record name to the class of this - field type. Remark that the fields always verify the uniform - inheritance condition. If the optional ``>`` is given before the - record name, then the constructor name is automatically declared as - a coercion from the class of the last field type to the record name - (this may fail if the uniform inheritance condition is not - satisfied). +We allow the definition of *Structures with Inheritance* (or classes as records) +by extending the existing :cmd:`Record` macro. Its new syntax is: + +.. cmdv:: Record {? >} @ident {? @binders} : @sort := {? @ident} { {+; @ident :{? >} @term } }. + + The first identifier `ident` is the name of the defined record and + `sort` is its type. The optional identifier after ``:=`` is the name + of the constuctor (it will be ``Build_``\ `ident` if not given). + The other identifiers are the names of the fields, and the `term` + are their respective types. If ``:>`` is used instead of ``:`` in + the declaration of a field, then the name of this field is automatically + declared as a coercion from the record name to the class of this + field type. Remark that the fields always verify the uniform + inheritance condition. If the optional ``>`` is given before the + record name, then the constructor name is automatically declared as + a coercion from the class of the last field type to the record name + (this may fail if the uniform inheritance condition is not + satisfied). .. note:: diff --git a/doc/sphinx/addendum/miscellaneous-extensions.rst b/doc/sphinx/addendum/miscellaneous-extensions.rst index 3ed4ce762..80ea8a116 100644 --- a/doc/sphinx/addendum/miscellaneous-extensions.rst +++ b/doc/sphinx/addendum/miscellaneous-extensions.rst @@ -3,15 +3,10 @@ .. _miscellaneousextensions: Miscellaneous extensions -======================= - -.. contents:: - :local: - :depth: 1 ----- +======================== Program derivation ------------------ +------------------ |Coq| comes with an extension called ``Derive``, which supports program derivation. Typically in the style of Bird and Meertens or derivations @@ -25,7 +20,7 @@ The first `ident` can appear in `term`. This command opens a new proof presenting the user with a goal for term in which the name `ident` is bound to an existential variable `?x` (formally, there are other goals standing for the existential variables but they are shelved, as -described in Section :ref:`TODO-8.17.4`). +described in :tacn:`shelve`). When the proof ends two constants are defined: diff --git a/doc/sphinx/addendum/nsatz.rst b/doc/sphinx/addendum/nsatz.rst index ef9b3505d..387d61495 100644 --- a/doc/sphinx/addendum/nsatz.rst +++ b/doc/sphinx/addendum/nsatz.rst @@ -19,7 +19,7 @@ where :math:`P, Q, P₁,Q₁,\ldots,Pₛ, Qₛ` are polynomials and :math:`A` is domain, i.e. a commutative ring with no zero divisor. For example, :math:`A` can be :math:`\mathbb{R}`, :math:`\mathbb{Z}`, or :math:`\mathbb{Q}`. Note that the equality :math:`=` used in these goals can be -any setoid equality (see :ref:`TODO-27.2.2`) , not only Leibnitz equality. +any setoid equality (see :ref:`tactics-enabled-on-user-provided-relations`) , not only Leibnitz equality. It also proves formulas diff --git a/doc/sphinx/addendum/parallel-proof-processing.rst b/doc/sphinx/addendum/parallel-proof-processing.rst index 8c1b9d152..edb8676a5 100644 --- a/doc/sphinx/addendum/parallel-proof-processing.rst +++ b/doc/sphinx/addendum/parallel-proof-processing.rst @@ -39,14 +39,14 @@ Proof annotations To process a proof asynchronously |Coq| needs to know the precise statement of the theorem without looking at the proof. This requires some annotations if the theorem is proved inside a Section (see -Section :ref:`TODO-2.4`). +Section :ref:`section-mechanism`). When a section ends, |Coq| looks at the proof object to decide which section variables are actually used and hence have to be quantified in the statement of the theorem. To avoid making the construction of proofs mandatory when ending a section, one can start each proof with -the ``Proof using`` command (Section :ref:`TODO-7.1.5`) that declares which section -variables the theorem uses. +the ``Proof using`` command (Section :ref:`proof-editing-mode`) that +declares which section variables the theorem uses. The presence of ``Proof`` using is needed to process proofs asynchronously in interactive mode. diff --git a/doc/sphinx/addendum/program.rst b/doc/sphinx/addendum/program.rst index eb50e52dc..1c3fdeb43 100644 --- a/doc/sphinx/addendum/program.rst +++ b/doc/sphinx/addendum/program.rst @@ -135,7 +135,7 @@ support types, avoiding uses of proof-irrelevance that would come up when reasoning with equality on the subset types themselves. The next two commands are similar to their standard counterparts -Definition (see Section `TODO-1.3.2-Definition`_) and Fixpoint (see Section `TODO-1.3.4-Fixpoint`_) +:cmd:`Definition` and :cmd:`Fixpoint` in that they define constants. However, they may require the user to prove some goals to construct the final definitions. @@ -174,7 +174,7 @@ Program Definition .. TODO refer to production in alias -See also: Sections `TODO-6.10.1-Opaque`_, `TODO-6.10.2-Transparent`_, `TODO-8.7.5-unfold`_ +See also: Sections :ref:`vernac-controlling-the-reduction-strategies`, :tacn:`unfold` .. _program_fixpoint: @@ -196,7 +196,7 @@ The optional order annotation follows the grammar: + :g:`wf R x` which is equivalent to :g:`measure x (R)`. The structural fixpoint operator behaves just like the one of |Coq| (see -Section `TODO-1.3.4-Fixpoint`_), except it may also generate obligations. It works +:cmd:`Fixpoint`), except it may also generate obligations. It works with mutually recursive definitions too. .. coqtop:: reset none diff --git a/doc/sphinx/addendum/ring.rst b/doc/sphinx/addendum/ring.rst index b861892cb..ae666a0d4 100644 --- a/doc/sphinx/addendum/ring.rst +++ b/doc/sphinx/addendum/ring.rst @@ -701,7 +701,7 @@ for |Coq|’s type-checker. Let us see why: At each step of rewriting, the whole context is duplicated in the proof term. Then, a tactic that does hundreds of rewriting generates huge proof terms. Since ``ACDSimpl`` was too slow, Samuel Boutin rewrote -it using reflection (see his article in TACS’97 [Bou97]_). Later, it +it using reflection (see :cite:`Bou97`). Later, it was rewritten by Patrick Loiseleur: the new tactic does not any more require ``ACDSimpl`` to compile and it makes use of |bdi|-reduction not only to replace the rewriting steps, but also to achieve the diff --git a/doc/sphinx/addendum/type-classes.rst b/doc/sphinx/addendum/type-classes.rst index 5518da9ac..8861cac8a 100644 --- a/doc/sphinx/addendum/type-classes.rst +++ b/doc/sphinx/addendum/type-classes.rst @@ -148,11 +148,10 @@ database. Sections and contexts --------------------- -To ease the parametrization of developments by type classes, we -provide a new way to introduce variables into section contexts, -compatible with the implicit argument mechanism. The new command works -similarly to the ``Variables`` vernacular (:ref:`TODO-1.3.2-Definitions`), except it -accepts any binding context as argument. For example: +To ease the parametrization of developments by type classes, we provide a new +way to introduce variables into section contexts, compatible with the implicit +argument mechanism. The new command works similarly to the :cmd:`Variables` +vernacular, except it accepts any binding context as argument. For example: .. coqtop:: all @@ -333,7 +332,7 @@ Variants: .. cmd:: Program Instance - Switches the type-checking to Program (chapter :ref:`program`) and + Switches the type-checking to Program (chapter :ref:`programs`) and uses the obligation mechanism to manage missing fields. .. cmd:: Declare Instance diff --git a/doc/sphinx/biblio.bib b/doc/sphinx/biblio.bib index 247f32103..ef50923c7 100644 --- a/doc/sphinx/biblio.bib +++ b/doc/sphinx/biblio.bib @@ -675,7 +675,6 @@ s}, author = {G. Huet}, booktitle = {A perspective in Theoretical Computer Science. Commemorative Volume for Gift Siromoney}, editor = {R. Narasimhan}, - note = {Also in~\cite{CoC89}}, publisher = {World Scientific Publishing}, title = {{The Constructive Engine}}, year = {1989} @@ -815,11 +814,12 @@ of the {ML} language}, } @inproceedings{Luttik97specificationof, - Author = {Sebastiaan P. Luttik and Eelco Visser}, - Booktitle = {2nd International Workshop on the Theory and Practice of Algebraic Specifications (ASF+SDF'97), Electronic Workshops in Computing}, - Publisher = {Springer-Verlag}, - Title = {Specification of Rewriting Strategies}, - Year = {1997}} + author = {Sebastiaan P. Luttik and Eelco Visser}, + booktitle = {2nd International Workshop on the Theory and Practice of Algebraic Specifications (ASF+SDF'97), Electronic Workshops in Computing}, + publisher = {Springer-Verlag}, + title = {Specification of Rewriting Strategies}, + year = {1997} +} @Book{MaL84, author = {{P. Martin-L\"of}}, diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst index 8b1d0e723..296330607 100644 --- a/doc/sphinx/index.rst +++ b/doc/sphinx/index.rst @@ -16,6 +16,7 @@ Table of contents .. toctree:: :caption: The language + language/gallina-specification-language language/gallina-extensions language/coq-library language/cic @@ -27,6 +28,7 @@ Table of contents proof-engine/vernacular-commands proof-engine/proof-handling proof-engine/tactics + proof-engine/ltac proof-engine/detailed-tactic-examples proof-engine/ssreflect-proof-language diff --git a/doc/sphinx/introduction.rst b/doc/sphinx/introduction.rst index 67de2ae68..4a313df0c 100644 --- a/doc/sphinx/introduction.rst +++ b/doc/sphinx/introduction.rst @@ -60,7 +60,7 @@ continuous reading. However, it has some structure that is explained below. - The first part describes the specification language, |Gallina|. - Chapters :ref:`thegallinaspecificationlanguage` and :ref:`extensionsofgallina` describe the concrete + Chapters :ref:`gallinaspecificationlanguage` and :ref:`extensionsofgallina` describe the concrete syntax as well as the meaning of programs, theorems and proofs in the Calculus of Inductive Constructions. Chapter :ref:`thecoqlibrary` describes the standard library of |Coq|. Chapter :ref:`calculusofinductiveconstructions` is a mathematical description @@ -76,7 +76,7 @@ below. Chapter :ref:`proofhandling`. In Chapter :ref:`tactics`, all commands that realize one or more steps of the proof are presented: we call them *tactics*. The language to combine these tactics into complex proof - strategies is given in Chapter :ref:`thetacticlanguage`. Examples of tactics + strategies is given in Chapter :ref:`ltac`. Examples of tactics are described in Chapter :ref:`detailedexamplesoftactics`. - The third part describes how to extend the syntax of |Coq|. It diff --git a/doc/sphinx/language/cic.rst b/doc/sphinx/language/cic.rst index 13d20d7cf..5a2aa0a1f 100644 --- a/doc/sphinx/language/cic.rst +++ b/doc/sphinx/language/cic.rst @@ -97,7 +97,7 @@ ensure the existence of a mapping of the universes to the positive integers, the graph of constraints must remain acyclic. Typing expressions that violate the acyclicity of the graph of constraints results in a Universe inconsistency error (see also Section -:ref:`TODO-2.10`). +:ref:`printing-universes`). .. _Terms: @@ -401,9 +401,11 @@ can decide if two programs are *intentionally* equal (one says *convertible*). Convertibility is described in this section. -.. _β-reduction: +.. _beta-reduction: + +β-reduction +~~~~~~~~~~~ -**β-reduction.** We want to be able to identify some terms as we can identify the application of a function to a given argument with its result. For instance the identity function over a given type T can be written @@ -427,9 +429,11 @@ theoretically of great importance but we will not detail them here and refer the interested reader to :cite:`Coq85`. -.. _ι-reduction: +.. _iota-reduction: + +ι-reduction +~~~~~~~~~~~ -**ι-reduction.** A specific conversion rule is associated to the inductive objects in the global environment. We shall give later on (see Section :ref:`Well-formed-inductive-definitions`) the precise rules but it @@ -438,9 +442,11 @@ constructor behaves as expected. This reduction is called ι-reduction and is more precisely studied in :cite:`Moh93,Wer94`. -.. _δ-reduction: +.. _delta-reduction: + +δ-reduction +~~~~~~~~~~~ -**δ-reduction.** We may have variables defined in local contexts or constants defined in the global environment. It is legal to identify such a reference with its value, that is to expand (or unfold) it into its value. This @@ -461,9 +467,11 @@ reduction is called δ-reduction and shows as follows. E[Γ] ⊢ c~\triangleright_δ~t -.. _ζ-reduction: +.. _zeta-reduction: + +ζ-reduction +~~~~~~~~~~~ -**ζ-reduction.** |Coq| allows also to remove local definitions occurring in terms by replacing the defined variable by its value. The declaration being destroyed, this reduction differs from δ-reduction. It is called @@ -478,9 +486,11 @@ destroyed, this reduction differs from δ-reduction. It is called E[Γ] ⊢ \letin{x}{u}{t}~\triangleright_ζ~\subst{t}{x}{u} -.. _η-expansion: +.. _eta-expansion: + +η-expansion +~~~~~~~~~~~ -**η-expansion.** Another important concept is η-expansion. It is legal to identify any term :math:`t` of functional type :math:`∀ x:T, U` with its so-called η-expansion @@ -517,9 +527,11 @@ for :math:`x` an arbitrary variable name fresh in :math:`t`. convertible to the type of the original term :math:`∀ x:\Type(1),\Type(1).` -.. _Convertibility: +.. _convertibility: + +Convertibility +~~~~~~~~~~~~~~ -**Convertibility.** Let us write :math:`E[Γ] ⊢ t \triangleright u` for the contextual closure of the relation :math:`t` reduces to :math:`u` in the global environment :math:`E` and local context :math:`Γ` with one of the previous @@ -709,8 +721,6 @@ called the *context of parameters*. Furthermore, we must have that each :math:`T` in :math:`(t:T)∈Γ_I` can be written as: :math:`∀Γ_P,∀Γ_{\mathit{Arr}(t)}, S` where :math:`Γ_{\mathit{Arr}(t)}` is called the *Arity* of the inductive type t and :math:`S` is called the sort of the inductive type t (not to be confused with :math:`\Sort` which is the set of sorts). - - ** Examples** The declaration for parameterized lists is: .. math:: @@ -825,8 +835,9 @@ to inconsistent systems. We restrict ourselves to definitions which satisfy a syntactic criterion of positivity. Before giving the formal rules, we need a few definitions: +Arity of a given sort ++++++++++++++++++++++ -**Type is an Arity of Sort S.** A type :math:`T` is an *arity of sort s* if it converts to the sort s or to a product :math:`∀ x:T,U` with :math:`U` an arity of sort s. @@ -836,7 +847,8 @@ product :math:`∀ x:T,U` with :math:`U` an arity of sort s. :math:`\Prop`. -**Type is an Arity.** +Arity ++++++ A type :math:`T` is an *arity* if there is a :math:`s∈ \Sort` such that :math:`T` is an arity of sort s. @@ -846,32 +858,34 @@ sort s. :math:`A→ Set` and :math:`∀ A:\Prop,A→ \Prop` are arities. -**Type of Constructor of I.** +Type constructor +++++++++++++++++ We say that T is a *type of constructor of I* in one of the following two cases: - + :math:`T` is :math:`(I~t_1 … t_n )` + :math:`T` is :math:`∀ x:U,T'` where :math:`T'` is also a type of constructor of :math:`I` - - .. example:: :math:`\nat` and :math:`\nat→\nat` are types of constructor of :math:`\nat`. :math:`∀ A:Type,\List~A` and :math:`∀ A:Type,A→\List~A→\List~A` are types of constructor of :math:`\List`. -**Positivity Condition.** +.. _positivity: + +Positivity Condition +++++++++++++++++++++ + The type of constructor :math:`T` will be said to *satisfy the positivity condition* for a constant :math:`X` in the following cases: - + :math:`T=(X~t_1 … t_n )` and :math:`X` does not occur free in any :math:`t_i` + :math:`T=∀ x:U,V` and :math:`X` occurs only strictly positively in :math:`U` and the type :math:`V` satisfies the positivity condition for :math:`X`. - -**Occurs Strictly Positively.** +Strict positivity ++++++++++++++++++ + The constant :math:`X` *occurs strictly positively* in :math:`T` in the following cases: @@ -891,11 +905,12 @@ cases: any of the :math:`t_i`, and the (instantiated) types of constructor :math:`\subst{C_i}{p_j}{a_j}_{j=1… m}` of :math:`I` satisfy the nested positivity condition for :math:`X` -**Nested Positivity Condition.** +Nested Positivity ++++++++++++++++++ + The type of constructor :math:`T` of :math:`I` *satisfies the nested positivity condition* for a constant :math:`X` in the following cases: - + :math:`T=(I~b_1 … b_m~u_1 … u_p)`, :math:`I` is an inductive definition with :math:`m` parameters and :math:`X` does not occur in any :math:`u_i` + :math:`T=∀ x:U,V` and :math:`X` occurs only strictly positively in :math:`U` and the type :math:`V` @@ -942,12 +957,11 @@ For instance, if one considers the type │ ╰─ list satisfies the positivity condition for list A ... (bullet 1) - - - .. _Correctness-rules: -**Correctness rules.** +Correctness rules ++++++++++++++++++ + We shall now describe the rules allowing the introduction of a new inductive definition. @@ -1014,7 +1028,9 @@ has type :math:`\Type(k)` with :math:`k<j` and :math:`k≤ i`. .. _Template-polymorphism: -**Template polymorphism.** +Template polymorphism ++++++++++++++++++++++ + Inductive types declared in Type are polymorphic over their arguments in Type. If :math:`A` is an arity of some sort and s is a sort, we write :math:`A_{/s}` for the arity obtained from :math:`A` by replacing its sort with s. @@ -1058,7 +1074,7 @@ provided that the following side conditions hold: we have :math:`(E[Γ_{I′} ;Γ_{P′}] ⊢ C_i : s_{q_i})_{i=1… n}` ; + the sorts :math:`s_i` are such that all eliminations, to :math:`\Prop`, :math:`\Set` and :math:`\Type(j)`, are allowed - (see Section Destructors_). + (see Section :ref:`Destructors`). @@ -1088,14 +1104,14 @@ The sorts :math:`s_j` are chosen canonically so that each :math:`s_j` is minimal respect to the hierarchy :math:`\Prop ⊂ \Set_p ⊂ \Type` where :math:`\Set_p` is predicative :math:`\Set`. More precisely, an empty or small singleton inductive definition (i.e. an inductive definition of which all inductive types are -singleton – see paragraph Destructors_) is set in :math:`\Prop`, a small non-singleton +singleton – see Section :ref:`Destructors`) is set in :math:`\Prop`, a small non-singleton inductive type is set in :math:`\Set` (even in case :math:`\Set` is impredicative – see Section The-Calculus-of-Inductive-Construction-with-impredicative-Set_), and otherwise in the Type hierarchy. Note that the side-condition about allowed elimination sorts in the rule **Ind-Family** is just to avoid to recompute the allowed elimination -sorts at each instance of a pattern-matching (see section Destructors_). As +sorts at each instance of a pattern-matching (see Section :ref:`Destructors`). As an example, let us consider the following definition: .. example:: @@ -1111,7 +1127,7 @@ in the Type hierarchy. Here, the parameter :math:`A` has this property, hence, if :g:`option` is applied to a type in :math:`\Set`, the result is in :math:`\Set`. Note that if :g:`option` is applied to a type in :math:`\Prop`, then, the result is not set in :math:`\Prop` but in :math:`\Set` still. This is because :g:`option` is not a singleton type -(see section Destructors_) and it would lose the elimination to :math:`\Set` and :math:`\Type` +(see Section :ref:`Destructors`) and it would lose the elimination to :math:`\Set` and :math:`\Type` if set in :math:`\Prop`. .. example:: @@ -1219,9 +1235,11 @@ Coquand in :cite:`Coq92`. One is the definition by pattern-matching. The second one is a definition by guarded fixpoints. -.. _The-match…with-end-construction: +.. _match-construction: + +The match ... with ... end construction ++++++++++++++++++++++++++++++++++++++++ -**The match…with …end construction** The basic idea of this operator is that we have an object :math:`m` in an inductive type :math:`I` and we want to prove a property which possibly depends on :math:`m`. For this, it is enough to prove the property for @@ -1278,7 +1296,7 @@ and :math:`I:A` and :math:`λ a x . P : B` then by :math:`[I:A|B]` we mean that :math:`λ a x . P` with :math:`m` in the above match-construct. -.. _Notations: +.. _cic_notations: **Notations.** The :math:`[I:A|B]` is defined as the smallest relation satisfying the following rules: We write :math:`[I|B]` for :math:`[I:A|B]` where :math:`A` is the type of :math:`I`. @@ -1625,9 +1643,8 @@ Given a variable :math:`y` of type an inductive definition in a declaration ones in which one of the :math:`I_l` occurs) are structurally smaller than y. -The following definitions are correct, we enter them using the ``Fixpoint`` -command as described in Section :ref:`TODO-1.3.4` and show the internal -representation. +The following definitions are correct, we enter them using the :cmd:`Fixpoint` +command and show the internal representation. .. example:: .. coqtop:: all @@ -1684,7 +1701,7 @@ possible: **Mutual induction** The principles of mutual induction can be automatically generated -using the Scheme command described in Section :ref:`TODO-13.1`. +using the Scheme command described in Section :ref:`proofschemes-induction-principles`. .. _Admissible-rules-for-global-environments: diff --git a/doc/sphinx/language/coq-library.rst b/doc/sphinx/language/coq-library.rst index 82ced65b4..6af6e7897 100644 --- a/doc/sphinx/language/coq-library.rst +++ b/doc/sphinx/language/coq-library.rst @@ -19,7 +19,7 @@ The |Coq| library is structured into two parts: developments of |Coq| axiomatizations about sets, lists, sorting, arithmetic, etc. This library comes with the system and its modules are directly accessible through the ``Require`` command (see - Section :ref:`TODO-6.5.1-Require`); + Section :ref:`compiled-files`); In addition, user-provided libraries or developments are provided by |Coq| users' community. These libraries and developments are available @@ -48,6 +48,7 @@ at the |Coq| root directory; this includes the modules ``Tactics``. Module ``Logic_Type`` also makes it in the initial state. +.. _init-notations: Notations ~~~~~~~~~ @@ -90,6 +91,8 @@ Notation Precedence Associativity ``_ ^ _`` 30 right ================ ============ =============== +.. _coq-library-logic: + Logic ~~~~~ @@ -521,7 +524,7 @@ provides a scope ``nat_scope`` gathering standard notations for common operations (``+``, ``*``) and a decimal notation for numbers, allowing for instance to write ``3`` for :g:`S (S (S O)))`. This also works on the left hand side of a ``match`` expression (see for example -section :ref:`TODO-refine-example`). This scope is opened by default. +section :tacn:`refine`). This scope is opened by default. .. example:: @@ -753,7 +756,7 @@ subdirectories: These directories belong to the initial load path of the system, and the modules they provide are compiled at installation time. So they are directly accessible with the command ``Require`` (see -Section :ref:`TODO-6.5.1-Require`). +Section :ref:`compiled-files`). The different modules of the |Coq| standard library are documented online at http://coq.inria.fr/stdlib. @@ -927,9 +930,8 @@ tactics (see Chapter :ref:`tactics`), there are also: Goal forall x y z:R, x * y * z <> 0. intros; split_Rmult. -These tactics has been written with the tactic language Ltac -described in Chapter :ref:`thetacticlanguage`. - +These tactics has been written with the tactic language |Ltac| +described in Chapter :ref:`ltac`. List library ~~~~~~~~~~~~ diff --git a/doc/sphinx/language/gallina-extensions.rst b/doc/sphinx/language/gallina-extensions.rst index 687775980..f474eade7 100644 --- a/doc/sphinx/language/gallina-extensions.rst +++ b/doc/sphinx/language/gallina-extensions.rst @@ -183,7 +183,7 @@ other arguments are the parameters of the inductive type. .. note:: Induction schemes are automatically generated for inductive records. Automatic generation of induction schemes for non-recursive records defined with the ``Record`` keyword can be activated with the - ``Nonrecursive Elimination Schemes`` option (see :ref:`TODO-13.1.1-nonrecursive-elimination-schemes`). + ``Nonrecursive Elimination Schemes`` option (see :ref:`proofschemes-induction-principles`). .. note:: ``Structure`` is a synonym of the keyword ``Record``. @@ -193,9 +193,9 @@ other arguments are the parameters of the inductive type. This message is followed by an explanation of this impossibility. There may be three reasons: - #. The name `ident` already exists in the environment (see Section :ref:`TODO-1.3.1-axioms`). + #. The name `ident` already exists in the environment (see :cmd:`Axiom`). #. The body of `ident` uses an incorrect elimination for - `ident` (see Sections :ref:`TODO-1.3.4-fixpoint` and :ref:`TODO-4.5.3-case-expr`). + `ident` (see :cmd:`Fixpoint` and :ref:`Destructors`). #. The type of the projections `ident` depends on previous projections which themselves could not be defined. @@ -212,9 +212,9 @@ other arguments are the parameters of the inductive type. During the definition of the one-constructor inductive definition, all the errors of inductive definitions, as described in Section -:ref:`TODO-1.3.3-inductive-definitions`, may also occur. +:ref:`gallina-inductive-definitions`, may also occur. -**See also** Coercions and records in Section :ref:`TODO-18.9-coercions-and-records` of the chapter devoted to coercions. +**See also** Coercions and records in Section :ref:`coercions-classes-as-records` of the chapter devoted to coercions. .. _primitive_projections: @@ -316,7 +316,7 @@ printed back as :g:`match` constructs. Variants and extensions of :g:`match` ------------------------------------- -.. _extended pattern-matching: +.. _mult-match: Multiple and nested pattern-matching ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -330,8 +330,9 @@ into a sequence of match on simple patterns. Especially, a construction defined using the extended match is generally printed under its expanded form (see ``Set Printing Matching`` in :ref:`controlling-match-pp`). -See also: :ref:`extended pattern-matching`. +See also: :ref:`extendedpatternmatching`. +.. _if-then-else: Pattern-matching on boolean values: the if expression ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -626,7 +627,7 @@ The following experimental command is available when the ``FunInd`` library has This command can be seen as a generalization of ``Fixpoint``. It is actually a wrapper for several ways of defining a function *and other useful related objects*, namely: an induction principle that reflects the recursive -structure of the function (see Section :ref:`TODO-8.5.5-functional-induction`) and its fixpoint equality. +structure of the function (see :tacn:`function induction`) and its fixpoint equality. The meaning of this declaration is to define a function ident, similarly to ``Fixpoint`. Like in ``Fixpoint``, the decreasing argument must be given (unless the function is not recursive), but it might not @@ -639,8 +640,8 @@ The ``Function`` construction also enjoys the ``with`` extension to define mutually recursive definitions. However, this feature does not work for non structurally recursive functions. -See the documentation of functional induction (:ref:`TODO-8.5.5-functional-induction`) -and ``Functional Scheme`` (:ref:`TODO-13.2-functional-scheme`) for how to use +See the documentation of functional induction (:tacn:`function induction`) +and ``Functional Scheme`` (:ref:`functional-scheme`) for how to use the induction principle to easily reason about the function. Remark: To obtain the right principle, it is better to put rigid @@ -711,7 +712,7 @@ terminating functions. `functional inversion` will not be available for the function. -See also: :ref:`TODO-13.2-generating-ind-principles` and ref:`TODO-8.5.5-functional-induction` +See also: :ref:`functional-scheme` and :tacn:`function induction` Depending on the ``{…}`` annotation, different definition mechanisms are used by ``Function``. A more precise description is given below. @@ -722,7 +723,7 @@ used by ``Function``. A more precise description is given below. the following are defined: + `ident_rect`, `ident_rec` and `ident_ind`, which reflect the pattern - matching structure of `term` (see the documentation of :ref:`TODO-1.3.3-Inductive`); + matching structure of `term` (see :cmd:`Inductive`); + The inductive `R_ident` corresponding to the graph of `ident` (silently); + `ident_complete` and `ident_correct` which are inversion information linking the function and its graph. @@ -771,13 +772,14 @@ used by ``Function``. A more precise description is given below. hand. Remark: Proof obligations are presented as several subgoals belonging to a Lemma `ident`\ :math:`_{\sf tcc}`. +.. _section-mechanism: Section mechanism ----------------- The sectioning mechanism can be used to to organize a proof in structured sections. Then local declarations become available (see -Section :ref:`TODO-1.3.2-Definitions`). +Section :ref:`gallina-definitions`). .. cmd:: Section @ident. @@ -847,7 +849,7 @@ together, as well as a means of massive abstraction. In the syntax of module application, the ! prefix indicates that any `Inline` directive in the type of the functor arguments will be ignored -(see :ref:`named_module_type` below). +(see the ``Module Type`` command below). .. cmd:: Module @ident. @@ -933,8 +935,6 @@ Reserved commands inside an interactive module is equivalent to an interactive module where each `module_expression` is included. -.. _named_module_type: - .. cmd:: Module Type @ident. This command is used to start an interactive module type `ident`. @@ -1195,7 +1195,7 @@ component is equal ``nat`` and hence ``M1.T`` as specified. Check T. Some features defined in modules are activated only when a module is -imported. This is for instance the case of notations (see :ref:`TODO-12.1-Notations`). +imported. This is for instance the case of notations (see :ref:`Notations`). Declarations made with the Local flag are never imported by theImport command. Such declarations are only accessible through their fully @@ -1241,13 +1241,11 @@ qualified name. This option (off by default) disables the printing of the types of fields, leaving only their names, for the commands ``Print Module`` and ``Print Module Type``. -.. cmd:: Locate Module @qualid. - - Prints the full name of the module `qualid`. - Libraries and qualified names --------------------------------- +.. _names-of-libraries: + Names of libraries ~~~~~~~~~~~~~~~~~~ @@ -1255,15 +1253,16 @@ The theories developed in |Coq| are stored in *library files* which are hierarchically classified into *libraries* and *sublibraries*. To express this hierarchy, library names are represented by qualified identifiers qualid, i.e. as list of identifiers separated by dots (see -:ref:`TODO-1.2.3-identifiers`). For instance, the library file ``Mult`` of the standard +:ref:`gallina-identifiers`). For instance, the library file ``Mult`` of the standard |Coq| library ``Arith`` is named ``Coq.Arith.Mult``. The identifier that starts the name of a library is called a *library root*. All library files of the standard library of |Coq| have the reserved root |Coq| but library file names based on other roots can be obtained by using |Coq| commands -(coqc, coqtop, coqdep, …) options ``-Q`` or ``-R`` (see :ref:`TODO-14.3.3-command-line-options`). +(coqc, coqtop, coqdep, …) options ``-Q`` or ``-R`` (see :ref:`command-line-options`). Also, when an interactive |Coq| session starts, a library of root ``Top`` is -started, unless option ``-top`` or ``-notop`` is set (see :ref:`TODO-14.3.3-command-line-options`). +started, unless option ``-top`` or ``-notop`` is set (see :ref:`command-line-options`). +.. _qualified-names: Qualified names ~~~~~~~~~~~~~~~ @@ -1298,13 +1297,13 @@ names also applies to library file names. |Coq| maintains a table called the name table which maps partially qualified names of constructions to absolute names. This table is updated by the -commands ``Require`` (see :ref:`TODO-6.5.1-Require`), Import and Export (see :ref:`import_qualid`) and +commands :cmd:`Require`, :cmd:`Import` and :cmd:`Export` and also each time a new declaration is added to the context. An absolute name is called visible from a given short or partially qualified name when this latter name is enough to denote it. This means that the short or partially qualified name is mapped to the absolute name in |Coq| name table. Definitions flagged as Local are only accessible with -their fully qualified name (see :ref:`TODO-1.3.2-definitions`). +their fully qualified name (see :ref:`gallina-definitions`). It may happen that a visible name is hidden by the short name or a qualified name of another construction. In this case, the name that @@ -1326,16 +1325,15 @@ accessible, absolute names can never be hidden. Locate nat. -See also: Command Locate in :ref:`TODO-6.3.10-locate-qualid` and Locate Library in -:ref:`TODO-6.6.11-locate-library`. +See also: Commands :cmd:`Locate` and :cmd:`Locate Library`. +.. _libraries-and-filesystem: Libraries and filesystem ~~~~~~~~~~~~~~~~~~~~~~~~ -Please note that the questions described here have been subject to -redesign in |Coq| v8.5. Former versions of |Coq| use the same terminology -to describe slightly different things. +.. note:: The questions described here have been subject to redesign in |Coq| 8.5. + Former versions of |Coq| use the same terminology to describe slightly different things. Compiled files (``.vo`` and ``.vio``) store sub-libraries. In order to refer to them inside |Coq|, a translation from file-system names to |Coq| names @@ -1371,7 +1369,7 @@ translation and with an empty logical prefix. The command line option ``-R`` is a variant of ``-Q`` which has the strictly same behavior regarding loadpaths, but which also makes the corresponding ``.vo`` files available through their short names in a way -not unlike the ``Import`` command (see :ref:`import_qualid`). For instance, ``-R`` `path` ``Lib`` +not unlike the ``Import`` command (see :ref:`here <import_qualid>`). For instance, ``-R`` `path` ``Lib`` associates to the ``filepath/fOO/Bar/File.vo`` the logical name ``Lib.fOO.Bar.File``, but allows this file to be accessed through the short names ``fOO.Bar.File,Bar.File`` and ``File``. If several files with @@ -1379,7 +1377,7 @@ identical base name are present in different subdirectories of a recursive loadpath, which of these files is found first may be system- dependent and explicit qualification is recommended. The ``From`` argument of the ``Require`` command can be used to bypass the implicit shortening -by providing an absolute root to the required file (see :ref:`TODO-6.5.1-require-qualid`). +by providing an absolute root to the required file (see :ref:`compiled-files`). There also exists another independent loadpath mechanism attached to OCaml object files (``.cmo`` or ``.cmxs``) rather than |Coq| object @@ -1387,11 +1385,12 @@ files as described above. The OCaml loadpath is managed using the option ``-I`` `path` (in the OCaml world, there is neither a notion of logical name prefix nor a way to access files in subdirectories of path). See the command ``Declare`` ``ML`` ``Module`` in -:ref:`TODO-6.5-compiled-files` to understand the need of the OCaml loadpath. +:ref:`compiled-files` to understand the need of the OCaml loadpath. -See :ref:`TODO-14.3.3-command-line-options` for a more general view over the |Coq| command +See :ref:`command-line-options` for a more general view over the |Coq| command line options. +.. _ImplicitArguments: Implicit arguments ------------------ @@ -1586,6 +1585,7 @@ Declaring Implicit Arguments To set implicit arguments *a posteriori*, one can use the command: .. cmd:: Arguments @qualid {* @possibly_bracketed_ident }. + :name: Arguments (implicits) where the list of `possibly_bracketed_ident` is a prefix of the list of arguments of `qualid` where the ones to be declared implicit are @@ -1799,6 +1799,8 @@ declares implicit arguments to be automatically inserted when a function is partially applied and the next argument of the function is an implicit one. +.. _explicit-applications: + Explicit applications ~~~~~~~~~~~~~~~~~~~~~ @@ -2098,6 +2100,7 @@ implicitly, as maximally-inserted arguments. In these binders, the binding name for the bound object is optional, whereas the type is mandatory, dually to regular binders. +.. _Coercions: Coercions --------- @@ -2136,21 +2139,24 @@ Otherwise said, ``Set Printing All`` includes the effects of the commands ``Unset Printing Projections``, and ``Unset Printing Notations``. To reactivate the high-level printing features, use the command ``Unset Printing All``. +.. _printing-universes: + Printing universes ------------------ .. opt:: Printing Universes. -Turn this option on to activate the display of the actual level of each occurrence of ``Type``. -See :ref:`TODO-4.1.1-sorts` for details. This wizard option, in combination -with ``Set Printing All`` (see :ref:`printing_constructions_full`) can help to diagnose failures -to unify terms apparently identical but internally different in the -Calculus of Inductive Constructions. +Turn this option on to activate the display of the actual level of each +occurrence of :g:`Type`. See :ref:`Sorts` for details. This wizard option, in +combination with :opt:`Printing All` can help to diagnose failures to unify +terms apparently identical but internally different in the Calculus of Inductive +Constructions. The constraints on the internal level of the occurrences of Type -(see :ref:`TODO-4.1.1-sorts`) can be printed using the command +(see :ref:`Sorts`) can be printed using the command .. cmd:: Print {? Sorted} Universes. + :name: Print Universes If the optional ``Sorted`` option is given, each universe will be made equivalent to a numbered label reflecting its level (with a linear @@ -2158,12 +2164,13 @@ ordering) in the universe hierarchy. This command also accepts an optional output filename: -.. cmd:: Print {? Sorted} Universes @string. +.. cmdv:: Print {? Sorted} Universes @string. If `string` ends in ``.dot`` or ``.gv``, the constraints are printed in the DOT language, and can be processed by Graphviz tools. The format is unspecified if `string` doesn’t end in ``.dot`` or ``.gv``. +.. _existential-variables: Existential variables --------------------- @@ -2173,9 +2180,9 @@ subterms to eventually be replaced by actual subterms. Existential variables are generated in place of unsolvable implicit arguments or “_” placeholders when using commands such as ``Check`` (see -Section :ref:`TODO-6.3.1-check`) or when using tactics such as ``refine`` (see Section -:ref:`TODO-8.2.3-refine`), as well as in place of unsolvable instances when using -tactics such that ``eapply`` (see Section :ref:`TODO-8.2.4-apply`). An existential +Section :ref:`requests-to-the-environment`) or when using tactics such as +:tacn:`refine`, as well as in place of unsolvable instances when using +tactics such that :tacn:`eapply`. An existential variable is defined in a context, which is the context of variables of the placeholder which generated the existential variable, and a type, which is the expected type of the placeholder. @@ -2220,7 +2227,7 @@ existential variable used in the same context as its context of definition is wr Existential variables can be named by the user upon creation using the syntax ``?``\ `ident`. This is useful when the existential variable needs to be explicitly handled later in the script (e.g. -with a named-goal selector, see :ref:`TODO-9.2-goal-selectors`). +with a named-goal selector, see :ref:`goal-selectors`). .. _explicit-display-existentials: @@ -2245,7 +2252,7 @@ is not specified and is implementation-dependent. The inner tactic may use any variable defined in its scope, including repeated alternations between variables introduced by term binding as well as those introduced by tactic binding. The expression `tacexpr` can be any tactic -expression as described in :ref:`thetacticlanguage`. +expression as described in :ref:`ltac`. .. coqtop:: all @@ -2256,5 +2263,5 @@ using highly automated tactics without resorting to writing the proof-term by means of the interactive proof engine. This mechanism is comparable to the ``Declare Implicit Tactic`` command -defined at :ref:`TODO-8.9.7-implicit-automation`, except that the used +defined at :ref:`tactics-implicit-automation`, except that the used tactic is local to each hole instead of being declared globally. diff --git a/doc/sphinx/language/gallina-specification-language.rst b/doc/sphinx/language/gallina-specification-language.rst new file mode 100644 index 000000000..246f45b3e --- /dev/null +++ b/doc/sphinx/language/gallina-specification-language.rst @@ -0,0 +1,1362 @@ +.. _gallinaspecificationlanguage: + +------------------------------------ + The Gallina specification language +------------------------------------ + +This chapter describes Gallina, the specification language of Coq. It allows +developing mathematical theories and to prove specifications of programs. The +theories are built from axioms, hypotheses, parameters, lemmas, theorems and +definitions of constants, functions, predicates and sets. The syntax of logical +objects involved in theories is described in Section :ref:`term`. The +language of commands, called *The Vernacular* is described in Section +:ref:`vernacular`. + +In Coq, logical objects are typed to ensure their logical correctness. The +rules implemented by the typing algorithm are described in Chapter :ref:`calculusofinductiveconstructions`. + + +About the grammars in the manual +================================ + +Grammars are presented in Backus-Naur form (BNF). Terminal symbols are +set in black ``typewriter font``. In addition, there are special notations for +regular expressions. + +An expression enclosed in square brackets ``[…]`` means at most one +occurrence of this expression (this corresponds to an optional +component). + +The notation “``entry sep … sep entry``” stands for a non empty sequence +of expressions parsed by entry and separated by the literal “``sep``” [1]_. + +Similarly, the notation “``entry … entry``” stands for a non empty +sequence of expressions parsed by the “``entry``” entry, without any +separator between. + +At the end, the notation “``[entry sep … sep entry]``” stands for a +possibly empty sequence of expressions parsed by the “``entry``” entry, +separated by the literal “``sep``”. + + +Lexical conventions +=================== + +Blanks + Space, newline and horizontal tabulation are considered as blanks. + Blanks are ignored but they separate tokens. + +Comments + Comments in Coq are enclosed between ``(*`` and ``*)``, and can be nested. + They can contain any character. However, string literals must be + correctly closed. Comments are treated as blanks. + +Identifiers and access identifiers + Identifiers, written ident, are sequences of letters, digits, ``_`` and + ``'``, that do not start with a digit or ``'``. That is, they are + recognized by the following lexical class: + + .. productionlist:: coq + first_letter : a..z ∣ A..Z ∣ _ ∣ unicode-letter + subsequent_letter : a..z ∣ A..Z ∣ 0..9 ∣ _ ∣ ' ∣ unicode-letter ∣ unicode-id-part + ident : `first_letter` [`subsequent_letter` … `subsequent_letter`] + access_ident : . `ident` + + All characters are meaningful. In particular, identifiers are case- + sensitive. The entry ``unicode-letter`` non-exhaustively includes Latin, + Greek, Gothic, Cyrillic, Arabic, Hebrew, Georgian, Hangul, Hiragana + and Katakana characters, CJK ideographs, mathematical letter-like + symbols, hyphens, non-breaking space, … The entry ``unicode-id-part`` non- + exhaustively includes symbols for prime letters and subscripts. + + Access identifiers, written :token:`access_ident`, are identifiers prefixed by + `.` (dot) without blank. They are used in the syntax of qualified + identifiers. + +Natural numbers and integers + Numerals are sequences of digits. Integers are numerals optionally + preceded by a minus sign. + + .. productionlist:: coq + digit : 0..9 + num : `digit` … `digit` + integer : [-] `num` + +Strings + Strings are delimited by ``"`` (double quote), and enclose a sequence of + any characters different from ``"`` or the sequence ``""`` to denote the + double quote character. In grammars, the entry for quoted strings is + :production:`string`. + +Keywords + The following identifiers are reserved keywords, and cannot be + employed otherwise:: + + _ as at cofix else end exists exists2 fix for + forall fun if IF in let match mod Prop return + Set then Type using where with + +Special tokens + The following sequences of characters are special tokens:: + + ! % & && ( () ) * + ++ , - -> . .( .. + / /\ : :: :< := :> ; < <- <-> <: <= <> = + => =_D > >-> >= ? ?= @ [ \/ ] ^ { | |- + || } ~ + + Lexical ambiguities are resolved according to the “longest match” + rule: when a sequence of non alphanumerical characters can be + decomposed into several different ways, then the first token is the + longest possible one (among all tokens defined at this moment), and so + on. + +.. _term: + +Terms +===== + +Syntax of terms +--------------- + +The following grammars describe the basic syntax of the terms of the +*Calculus of Inductive Constructions* (also called Cic). The formal +presentation of Cic is given in Chapter :ref:`calculusofinductiveconstructions`. Extensions of this syntax +are given in Chapter :ref:`extensionsofgallina`. How to customize the syntax +is described in Chapter :ref:`syntaxextensionsandinterpretationscopes`. + +.. productionlist:: coq + term : forall `binders` , `term` + : | fun `binders` => `term` + : | fix `fix_bodies` + : | cofix `cofix_bodies` + : | let `ident` [`binders`] [: `term`] := `term` in `term` + : | let fix `fix_body` in `term` + : | let cofix `cofix_body` in `term` + : | let ( [`name` , … , `name`] ) [`dep_ret_type`] := `term` in `term` + : | let ' `pattern` [in `term`] := `term` [`return_type`] in `term` + : | if `term` [`dep_ret_type`] then `term` else `term` + : | `term` : `term` + : | `term` <: `term` + : | `term` :> + : | `term` -> `term` + : | `term` arg … arg + : | @ `qualid` [`term` … `term`] + : | `term` % `ident` + : | match `match_item` , … , `match_item` [`return_type`] with + : [[|] `equation` | … | `equation`] end + : | `qualid` + : | `sort` + : | num + : | _ + : | ( `term` ) + arg : `term` + : | ( `ident` := `term` ) + binders : `binder` … `binder` + binder : `name` + : | ( `name` … `name` : `term` ) + : | ( `name` [: `term`] := `term` ) + name : `ident` | _ + qualid : `ident` | `qualid` `access_ident` + sort : Prop | Set | Type + fix_bodies : `fix_body` + : | `fix_body` with `fix_body` with … with `fix_body` for `ident` + cofix_bodies : `cofix_body` + : | `cofix_body` with `cofix_body` with … with `cofix_body` for `ident` + fix_body : `ident` `binders` [annotation] [: `term`] := `term` + cofix_body : `ident` [`binders`] [: `term`] := `term` + annotation : { struct `ident` } + match_item : `term` [as `name`] [in `qualid` [`pattern` … `pattern`]] + dep_ret_type : [as `name`] `return_type` + return_type : return `term` + equation : `mult_pattern` | … | `mult_pattern` => `term` + mult_pattern : `pattern` , … , `pattern` + pattern : `qualid` `pattern` … `pattern` + : | @ `qualid` `pattern` … `pattern` + : | `pattern` as `ident` + : | `pattern` % `ident` + : | `qualid` + : | _ + : | num + : | ( `or_pattern` , … , `or_pattern` ) + or_pattern : `pattern` | … | `pattern` + + +Types +----- + +Coq terms are typed. Coq types are recognized by the same syntactic +class as :token`term`. We denote by :token:`type` the semantic subclass +of types inside the syntactic class :token:`term`. + +.. _gallina-identifiers: + +Qualified identifiers and simple identifiers +-------------------------------------------- + +*Qualified identifiers* (:token:`qualid`) denote *global constants* +(definitions, lemmas, theorems, remarks or facts), *global variables* +(parameters or axioms), *inductive types* or *constructors of inductive +types*. *Simple identifiers* (or shortly :token:`ident`) are a syntactic subset +of qualified identifiers. Identifiers may also denote local *variables*, +what qualified identifiers do not. + +Numerals +-------- + +Numerals have no definite semantics in the calculus. They are mere +notations that can be bound to objects through the notation mechanism +(see Chapter :ref:`syntaxextensionsandinterpretationscopes` for details). +Initially, numerals are bound to Peano’s representation of natural +numbers (see :ref:`datatypes`). + +.. note:: + + negative integers are not at the same level as :token:`num`, for this + would make precedence unnatural. + +Sorts +----- + +There are three sorts :g:`Set`, :g:`Prop` and :g:`Type`. + +- :g:`Prop` is the universe of *logical propositions*. The logical propositions + themselves are typing the proofs. We denote propositions by *form*. + This constitutes a semantic subclass of the syntactic class :token:`term`. + +- :g:`Set` is is the universe of *program types* or *specifications*. The + specifications themselves are typing the programs. We denote + specifications by *specif*. This constitutes a semantic subclass of + the syntactic class :token:`term`. + +- :g:`Type` is the type of :g:`Prop` and :g:`Set` + +More on sorts can be found in Section :ref:`sorts`. + +.. _binders: + +Binders +------- + +Various constructions such as :g:`fun`, :g:`forall`, :g:`fix` and :g:`cofix` +*bind* variables. A binding is represented by an identifier. If the binding +variable is not used in the expression, the identifier can be replaced by the +symbol :g:`_`. When the type of a bound variable cannot be synthesized by the +system, it can be specified with the notation ``(ident : type)``. There is also +a notation for a sequence of binding variables sharing the same type: +``(``:token:`ident`:math:`_1`…:token:`ident`:math:`_n` : :token:`type```)``. A +binder can also be any pattern prefixed by a quote, e.g. :g:`'(x,y)`. + +Some constructions allow the binding of a variable to value. This is +called a “let-binder”. The entry :token:`binder` of the grammar accepts +either an assumption binder as defined above or a let-binder. The notation in +the latter case is ``(ident := term)``. In a let-binder, only one +variable can be introduced at the same time. It is also possible to give +the type of the variable as follows: +``(ident : term := term)``. + +Lists of :token:`binder` are allowed. In the case of :g:`fun` and :g:`forall`, +it is intended that at least one binder of the list is an assumption otherwise +fun and forall gets identical. Moreover, parentheses can be omitted in +the case of a single sequence of bindings sharing the same type (e.g.: +:g:`fun (x y z : A) => t` can be shortened in :g:`fun x y z : A => t`). + +Abstractions +------------ + +The expression ``fun ident : type => term`` defines the +*abstraction* of the variable :token:`ident`, of type :token:`type`, over the term +:token:`term`. It denotes a function of the variable :token:`ident` that evaluates to +the expression :token:`term` (e.g. :g:`fun x : A => x` denotes the identity +function on type :g:`A`). The keyword :g:`fun` can be followed by several +binders as given in Section :ref:`binders`. Functions over +several variables are equivalent to an iteration of one-variable +functions. For instance the expression +“fun :token:`ident`\ :math:`_{1}` … :token:`ident`\ :math:`_{n}` +: :token:`type` => :token:`term`” +denotes the same function as “ fun :token:`ident`\ +:math:`_{1}` : :token:`type` => … +fun :token:`ident`\ :math:`_{n}` : :token:`type` => :token:`term`”. If +a let-binder occurs in +the list of binders, it is expanded to a let-in definition (see +Section :ref:`let-in`). + +Products +-------- + +The expression :g:`forall ident : type, term` denotes the +*product* of the variable :token:`ident` of type :token:`type`, over the term :token:`term`. +As for abstractions, :g:`forall` is followed by a binder list, and products +over several variables are equivalent to an iteration of one-variable +products. Note that :token:`term` is intended to be a type. + +If the variable :token:`ident` occurs in :token:`term`, the product is called +*dependent product*. The intention behind a dependent product +:g:`forall x : A, B` is twofold. It denotes either +the universal quantification of the variable :g:`x` of type :g:`A` +in the proposition :g:`B` or the functional dependent product from +:g:`A` to :g:`B` (a construction usually written +:math:`\Pi_{x:A}.B` in set theory). + +Non dependent product types have a special notation: :g:`A -> B` stands for +:g:`forall _ : A, B`. The *non dependent product* is used both to denote +the propositional implication and function types. + +Applications +------------ + +The expression :token:`term`\ :math:`_0` :token:`term`\ :math:`_1` denotes the +application of :token:`term`\ :math:`_0` to :token:`term`\ :math:`_1`. + +The expression :token:`term`\ :math:`_0` :token:`term`\ :math:`_1` ... +:token:`term`\ :math:`_n` denotes the application of the term +:token:`term`\ :math:`_0` to the arguments :token:`term`\ :math:`_1` ... then +:token:`term`\ :math:`_n`. It is equivalent to ( … ( :token:`term`\ :math:`_0` +:token:`term`\ :math:`_1` ) … ) :token:`term`\ :math:`_n` : associativity is to the +left. + +The notation ``(ident := term)`` for arguments is used for making +explicit the value of implicit arguments (see +Section :ref:`explicit-applications`). + +Type cast +--------- + +The expression ``term : type`` is a type cast expression. It enforces +the type of :token:`term` to be :token:`type`. + +``term <: type`` locally sets up the virtual machine for checking that +:token:`term` has type :token:`type`. + +Inferable subterms +------------------ + +Expressions often contain redundant pieces of information. Subterms that can be +automatically inferred by Coq can be replaced by the symbol ``_`` and Coq will +guess the missing piece of information. + +.. _let-in: + +Let-in definitions +------------------ + +``let`` :token:`ident` := :token:`term`:math:`_1` in :token:`term`:math:`_2` +denotes the local binding of :token:`term`:math:`_1` to the variable +:token:`ident` in :token:`term`:math:`_2`. There is a syntactic sugar for let-in +definition of functions: ``let`` :token:`ident` :token:`binder`:math:`_1` … +:token:`binder`:math:`_n` := :token:`term`:math:`_1` in :token:`term`:math:`_2` +stands for ``let`` :token:`ident` := ``fun`` :token:`binder`:math:`_1` … +:token:`binder`:math:`_n` => :token:`term`:math:`_1` in :token:`term`:math:`_2`. + +Definition by case analysis +--------------------------- + +Objects of inductive types can be destructurated by a case-analysis +construction called *pattern-matching* expression. A pattern-matching +expression is used to analyze the structure of an inductive objects and +to apply specific treatments accordingly. + +This paragraph describes the basic form of pattern-matching. See +Section :ref:`Mult-match` and Chapter :ref:`extendedpatternmatching` for the description +of the general form. The basic form of pattern-matching is characterized +by a single :token:`match_item` expression, a :token:`mult_pattern` restricted to a +single :token:`pattern` and :token:`pattern` restricted to the form +:token:`qualid` :token:`ident`. + +The expression match :token:`term`:math:`_0` :token:`return_type` with +:token:`pattern`:math:`_1` => :token:`term`:math:`_1` :math:`|` … :math:`|` +:token:`pattern`:math:`_n` => :token:`term`:math:`_n` end, denotes a +:token:`pattern-matching` over the term :token:`term`:math:`_0` (expected to be +of an inductive type :math:`I`). The terms :token:`term`:math:`_1`\ …\ +:token:`term`:math:`_n` are the :token:`branches` of the pattern-matching +expression. Each of :token:`pattern`:math:`_i` has a form :token:`qualid` +:token:`ident` where :token:`qualid` must denote a constructor. There should be +exactly one branch for every constructor of :math:`I`. + +The :token:`return_type` expresses the type returned by the whole match +expression. There are several cases. In the *non dependent* case, all +branches have the same type, and the :token:`return_type` is the common type of +branches. In this case, :token:`return_type` can usually be omitted as it can be +inferred from the type of the branches [2]_. + +In the *dependent* case, there are three subcases. In the first subcase, +the type in each branch may depend on the exact value being matched in +the branch. In this case, the whole pattern-matching itself depends on +the term being matched. This dependency of the term being matched in the +return type is expressed with an “as :token:`ident`” clause where :token:`ident` +is dependent in the return type. For instance, in the following example: + +.. coqtop:: in + + Inductive bool : Type := true : bool | false : bool. + Inductive eq (A:Type) (x:A) : A -> Prop := eq_refl : eq A x x. + Inductive or (A:Prop) (B:Prop) : Prop := + | or_introl : A -> or A B + | or_intror : B -> or A B. + + Definition bool_case (b:bool) : or (eq bool b true) (eq bool b false) := + match b as x return or (eq bool x true) (eq bool x false) with + | true => or_introl (eq bool true true) (eq bool true false) + (eq_refl bool true) + | false => or_intror (eq bool false true) (eq bool false false) + (eq_refl bool false) + end. + +the branches have respective types or :g:`eq bool true true :g:`eq bool true +false` and or :g:`eq bool false true` :g:`eq bool false false` while the whole +pattern-matching expression has type or :g:`eq bool b true` :g:`eq bool b +false`, the identifier :g:`x` being used to represent the dependency. Remark +that when the term being matched is a variable, the as clause can be +omitted and the term being matched can serve itself as binding name in +the return type. For instance, the following alternative definition is +accepted and has the same meaning as the previous one. + +.. coqtop:: in + + Definition bool_case (b:bool) : or (eq bool b true) (eq bool b false) := + match b return or (eq bool b true) (eq bool b false) with + | true => or_introl (eq bool true true) (eq bool true false) + (eq_refl bool true) + | false => or_intror (eq bool false true) (eq bool false false) + (eq_refl bool false) + end. + +The second subcase is only relevant for annotated inductive types such +as the equality predicate (see Section :ref:`Equality`), +the order predicate on natural numbers or the type of lists of a given +length (see Section :ref:`matching-dependent`). In this configuration, the +type of each branch can depend on the type dependencies specific to the +branch and the whole pattern-matching expression has a type determined +by the specific dependencies in the type of the term being matched. This +dependency of the return type in the annotations of the inductive type +is expressed using a “in I _ ... _ :token:`pattern`:math:`_1` ... +:token:`pattern`:math:`_n`” clause, where + +- :math:`I` is the inductive type of the term being matched; + +- the :g:`_` are matching the parameters of the inductive type: the + return type is not dependent on them. + +- the :token:`pattern`:math:`_i` are matching the annotations of the + inductive type: the return type is dependent on them + +- in the basic case which we describe below, each :token:`pattern`:math:`_i` + is a name :token:`ident`:math:`_i`; see :ref:`match-in-patterns` for the + general case + +For instance, in the following example: + +.. coqtop:: in + + Definition eq_sym (A:Type) (x y:A) (H:eq A x y) : eq A y x := + match H in eq _ _ z return eq A z x with + | eq_refl _ => eq_refl A x + end. + +the type of the branch has type :g:`eq A x x` because the third argument of +g:`eq` is g:`x` in the type of the pattern :g:`refl_equal`. On the contrary, the +type of the whole pattern-matching expression has type :g:`eq A y x` because the +third argument of eq is y in the type of H. This dependency of the case analysis +in the third argument of :g:`eq` is expressed by the identifier g:`z` in the +return type. + +Finally, the third subcase is a combination of the first and second +subcase. In particular, it only applies to pattern-matching on terms in +a type with annotations. For this third subcase, both the clauses as and +in are available. + +There are specific notations for case analysis on types with one or two +constructors: “if … then … else …” and “let (…, ” (see +Sections :ref:`if-then-else` and :ref:`let-in`). + +Recursive functions +------------------- + +The expression “fix :token:`ident`:math:`_1` :token:`binder`:math:`_1` : +:token:`type`:math:`_1` ``:=`` :token:`term`:math:`_1` with … with +:token:`ident`:math:`_n` :token:`binder`:math:`_n` : :token:`type`:math:`_n` +``:=`` :token:`term`:math:`_n` for :token:`ident`:math:`_i`” denotes the +:math:`i`\ component of a block of functions defined by mutual well-founded +recursion. It is the local counterpart of the :cmd:`Fixpoint` command. When +:math:`n=1`, the “for :token:`ident`:math:`_i`” clause is omitted. + +The expression “cofix :token:`ident`:math:`_1` :token:`binder`:math:`_1` : +:token:`type`:math:`_1` with … with :token:`ident`:math:`_n` :token:`binder`:math:`_n` +: :token:`type`:math:`_n` for :token:`ident`:math:`_i`” denotes the +:math:`i`\ component of a block of terms defined by a mutual guarded +co-recursion. It is the local counterpart of the ``CoFixpoint`` command. See +Section :ref:`CoFixpoint` for more details. When +:math:`n=1`, the “ for :token:`ident`:math:`_i`” clause is omitted. + +The association of a single fixpoint and a local definition have a special +syntax: “let fix f … := … in …” stands for “let f := fix f … := … in …”. The +same applies for co-fixpoints. + +.. _vernacular: + +The Vernacular +============== + +.. productionlist:: coq + sentence : `assumption` + : | `definition` + : | `inductive` + : | `fixpoint` + : | `assertion` `proof` + assumption : `assumption_keyword` `assums`. + assumption_keyword : Axiom | Conjecture + : | Parameter | Parameters + : | Variable | Variables + : | Hypothesis | Hypotheses + assums : `ident` … `ident` : `term` + : | ( `ident` … `ident` : `term` ) … ( `ident` … `ident` : `term` ) + definition : [Local] Definition `ident` [`binders`] [: `term`] := `term` . + : | Let `ident` [`binders`] [: `term`] := `term` . + inductive : Inductive `ind_body` with … with `ind_body` . + : | CoInductive `ind_body` with … with `ind_body` . + ind_body : `ident` [`binders`] : `term` := + : [[|] `ident` [`binders`] [:`term`] | … | `ident` [`binders`] [:`term`]] + fixpoint : Fixpoint `fix_body` with … with `fix_body` . + : | CoFixpoint `cofix_body` with … with `cofix_body` . + assertion : `assertion_keyword` `ident` [`binders`] : `term` . + assertion_keyword : Theorem | Lemma + : | Remark | Fact + : | Corollary | Proposition + : | Definition | Example + proof : Proof . … Qed . + : | Proof . … Defined . + : | Proof . … Admitted . + +.. todo:: This use of … in this grammar is inconsistent + +This grammar describes *The Vernacular* which is the language of +commands of Gallina. A sentence of the vernacular language, like in +many natural languages, begins with a capital letter and ends with a +dot. + +The different kinds of command are described hereafter. They all suppose +that the terms occurring in the sentences are well-typed. + +.. _gallina-assumptions: + +Assumptions +----------- + +Assumptions extend the environment with axioms, parameters, hypotheses +or variables. An assumption binds an :token:`ident` to a :token:`type`. It is accepted +by Coq if and only if this :token:`type` is a correct type in the environment +preexisting the declaration and if :token:`ident` was not previously defined in +the same module. This :token:`type` is considered to be the type (or +specification, or statement) assumed by :token:`ident` and we say that :token:`ident` +has type :token:`type`. + +.. _Axiom: + +.. cmd:: Axiom @ident : @term. + + This command links *term* to the name *ident* as its specification in + the global context. The fact asserted by *term* is thus assumed as a + postulate. + +.. exn:: @ident already exists + +.. cmdv:: Parameter @ident : @term. + + Is equivalent to ``Axiom`` :token:`ident` : :token:`term` + +.. cmdv:: Parameter {+ @ident } : @term. + + Adds parameters with specification :token:`term` + +.. cmdv:: Parameter {+ ( {+ @ident } : @term ) }. + + Adds blocks of parameters with different specifications. + +.. cmdv:: Parameters {+ ( {+ @ident } : @term ) }. + + Synonym of ``Parameter``. + +.. cmdv:: Local Axiom @ident : @term. + + Such axioms are never made accessible through their unqualified name by + :cmd:`Import` and its variants. You have to explicitly give their fully + qualified name to refer to them. + +.. cmdv:: Conjecture @ident : @term + + Is equivalent to ``Axiom`` :token:`ident` : :token:`term`. + +.. cmd:: Variable @ident : @term. + +This command links :token:`term` to the name :token:`ident` in the context of +the current section (see Section :ref:`section-mechanism` for a description of +the section mechanism). When the current section is closed, name :token:`ident` +will be unknown and every object using this variable will be explicitly +parametrized (the variable is *discharged*). Using the ``Variable`` command out +of any section is equivalent to using ``Local Parameter``. + +.. exn:: @ident already exists + +.. cmdv:: Variable {+ @ident } : @term. + + Links :token:`term` to each :token:`ident`. + +.. cmdv:: Variable {+ ( {+ @ident } : @term) }. + + Adds blocks of variables with different specifications. + +.. cmdv:: Variables {+ ( {+ @ident } : @term) }. + +.. cmdv:: Hypothesis {+ ( {+ @ident } : @term) }. + +.. cmdv:: Hypotheses {+ ( {+ @ident } : @term) }. + +Synonyms of ``Variable``. + +It is advised to use the keywords ``Axiom`` and ``Hypothesis`` for +logical postulates (i.e. when the assertion *term* is of sort ``Prop``), +and to use the keywords ``Parameter`` and ``Variable`` in other cases +(corresponding to the declaration of an abstract mathematical entity). + +.. _gallina-definitions: + +Definitions +----------- + +Definitions extend the environment with associations of names to terms. +A definition can be seen as a way to give a meaning to a name or as a +way to abbreviate a term. In any case, the name can later be replaced at +any time by its definition. + +The operation of unfolding a name into its definition is called +:math:`\delta`-conversion (see Section :ref:`delta-reduction`). A +definition is accepted by the system if and only if the defined term is +well-typed in the current context of the definition and if the name is +not already used. The name defined by the definition is called a +*constant* and the term it refers to is its *body*. A definition has a +type which is the type of its body. + +A formal presentation of constants and environments is given in +Section :ref:`typing-rules`. + +.. cmd:: Definition @ident := @term. + + This command binds :token:`term` to the name :token:`ident` in the environment, + provided that :token:`term` is well-typed. + +.. exn:: @ident already exists + +.. cmdv:: Definition @ident : @term := @term. + + It checks that the type of :token:`term`:math:`_2` is definitionally equal to + :token:`term`:math:`_1`, and registers :token:`ident` as being of type + :token:`term`:math:`_1`, and bound to value :token:`term`:math:`_2`. + + +.. cmdv:: Definition @ident {* @binder } : @term := @term. + + This is equivalent to ``Definition`` :token:`ident` : :g:`forall` + :token:`binder`:math:`_1` … :token:`binder`:math:`_n`, :token:`term`:math:`_1` := + fun :token:`binder`:math:`_1` … + :token:`binder`:math:`_n` => :token:`term`:math:`_2`. + +.. cmdv:: Local Definition @ident := @term. + + Such definitions are never made accessible through their + unqualified name by :cmd:`Import` and its variants. + You have to explicitly give their fully qualified name to refer to them. + +.. cmdv:: Example @ident := @term. + +.. cmdv:: Example @ident : @term := @term. + +.. cmdv:: Example @ident {* @binder } : @term := @term. + +These are synonyms of the Definition forms. + +.. exn:: The term @term has type @type while it is expected to have type @type + +See also :cmd:`Opaque`, :cmd:`Transparent`, :tac:`unfold`. + +.. cmd:: Let @ident := @term. + +This command binds the value :token:`term` to the name :token:`ident` in the +environment of the current section. The name :token:`ident` disappears when the +current section is eventually closed, and, all persistent objects (such +as theorems) defined within the section and depending on :token:`ident` are +prefixed by the let-in definition ``let`` :token:`ident` ``:=`` :token:`term` +``in``. Using the ``Let`` command out of any section is equivalent to using +``Local Definition``. + +.. exn:: @ident already exists + +.. cmdv:: Let @ident : @term := @term. + +.. cmdv:: Let Fixpoint @ident @fix_body {* with @fix_body}. + +.. cmdv:: Let CoFixpoint @ident @cofix_body {* with @cofix_body}. + +See also Sections :ref:`section-mechanism`, commands :cmd:`Opaque`, +:cmd:`Transparent`, and tactic :tacn:`unfold`. + +.. _gallina-inductive-definitions: + +Inductive definitions +--------------------- + +We gradually explain simple inductive types, simple annotated inductive +types, simple parametric inductive types, mutually inductive types. We +explain also co-inductive types. + +Simple inductive types +~~~~~~~~~~~~~~~~~~~~~~ + +The definition of a simple inductive type has the following form: + +.. cmd:: Inductive @ident : @sort := {? | } @ident : @type {* | @ident : @type } + +The name :token:`ident` is the name of the inductively defined type and +:token:`sort` is the universes where it lives. The :token:`ident` are the names +of its constructors and :token:`type` their respective types. The types of the +constructors have to satisfy a *positivity condition* (see Section +:ref:`positivity`) for :token:`ident`. This condition ensures the soundness of +the inductive definition. If this is the case, the :token:`ident` are added to +the environment with their respective types. Accordingly to the universe where +the inductive type lives (e.g. its type :token:`sort`), Coq provides a number of +destructors for :token:`ident`. Destructors are named ``ident_ind``, +``ident_rec`` or ``ident_rect`` which respectively correspond to +elimination principles on :g:`Prop`, :g:`Set` and :g:`Type`. The type of the +destructors expresses structural induction/recursion principles over objects of +:token:`ident`. We give below two examples of the use of the Inductive +definitions. + +The set of natural numbers is defined as: + +.. coqtop:: all + + Inductive nat : Set := + | O : nat + | S : nat -> nat. + +The type nat is defined as the least :g:`Set` containing :g:`O` and closed by +the :g:`S` constructor. The names :g:`nat`, :g:`O` and :g:`S` are added to the +environment. + +Now let us have a look at the elimination principles. They are three of them: +:g:`nat_ind`, :g:`nat_rec` and :g:`nat_rect`. The type of :g:`nat_ind` is: + +.. coqtop:: all + + Check nat_ind. + +This is the well known structural induction principle over natural +numbers, i.e. the second-order form of Peano’s induction principle. It +allows proving some universal property of natural numbers (:g:`forall +n:nat, P n`) by induction on :g:`n`. + +The types of :g:`nat_rec` and :g:`nat_rect` are similar, except that they pertain +to :g:`(P:nat->Set)` and :g:`(P:nat->Type)` respectively. They correspond to +primitive induction principles (allowing dependent types) respectively +over sorts ``Set`` and ``Type``. The constant ``ident_ind`` is always +provided, whereas ``ident_rec`` and ``ident_rect`` can be impossible +to derive (for example, when :token:`ident` is a proposition). + +.. coqtop:: in + + Inductive nat : Set := O | S (_:nat). + +In the case where inductive types have no annotations (next section +gives an example of such annotations), a constructor can be defined +by only giving the type of its arguments. + +Simple annotated inductive types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In an annotated inductive types, the universe where the inductive type +is defined is no longer a simple sort, but what is called an arity, +which is a type whose conclusion is a sort. + +As an example of annotated inductive types, let us define the +:g:`even` predicate: + +.. coqtop:: all + + Inductive even : nat -> Prop := + | even_0 : even O + | even_SS : forall n:nat, even n -> even (S (S n)). + +The type :g:`nat->Prop` means that even is a unary predicate (inductively +defined) over natural numbers. The type of its two constructors are the +defining clauses of the predicate even. The type of :g:`even_ind` is: + +.. coqtop:: all + + Check even_ind. + +From a mathematical point of view it asserts that the natural numbers satisfying +the predicate even are exactly in the smallest set of naturals satisfying the +clauses :g:`even_0` or :g:`even_SS`. This is why, when we want to prove any +predicate :g:`P` over elements of :g:`even`, it is enough to prove it for :g:`O` +and to prove that if any natural number :g:`n` satisfies :g:`P` its double +successor :g:`(S (S n))` satisfies also :g:`P`. This is indeed analogous to the +structural induction principle we got for :g:`nat`. + +.. exn:: Non strictly positive occurrence of @ident in @type + +.. exn:: The conclusion of @type is not valid; it must be built from @ident + +Parametrized inductive types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In the previous example, each constructor introduces a different +instance of the predicate even. In some cases, all the constructors +introduces the same generic instance of the inductive definition, in +which case, instead of an annotation, we use a context of parameters +which are binders shared by all the constructors of the definition. + +The general scheme is: + +.. cmdv:: Inductive @ident {+ @binder} : @term := {? | } @ident : @type {* | @ident : @type} + +Parameters differ from inductive type annotations in the fact that the +conclusion of each type of constructor :g:`term` invoke the inductive type with +the same values of parameters as its specification. + +A typical example is the definition of polymorphic lists: + +.. coqtop:: in + + Inductive list (A:Set) : Set := + | nil : list A + | cons : A -> list A -> list A. + +.. note:: + + In the type of :g:`nil` and :g:`cons`, we write :g:`(list A)` and not + just :g:`list`. The constructors :g:`nil` and :g:`cons` will have respectively + types: + + .. coqtop:: all + + Check nil. + Check cons. + + Types of destructors are also quantified with :g:`(A:Set)`. + +Variants +++++++++ + +.. coqtop:: in + + Inductive list (A:Set) : Set := nil | cons (_:A) (_:list A). + +This is an alternative definition of lists where we specify the +arguments of the constructors rather than their full type. + +.. coqtop:: in + + Variant sum (A B:Set) : Set := left : A -> sum A B | right : B -> sum A B. + +The ``Variant`` keyword is identical to the ``Inductive`` keyword, except +that it disallows recursive definition of types (in particular lists cannot +be defined with the Variant keyword). No induction scheme is generated for +this variant, unless :opt:`Nonrecursive Elimination Schemes` is set. + +.. exn:: The @num th argument of @ident must be @ident in @type + +New from Coq V8.1 ++++++++++++++++++ + +The condition on parameters for inductive definitions has been relaxed +since Coq V8.1. It is now possible in the type of a constructor, to +invoke recursively the inductive definition on an argument which is not +the parameter itself. + +One can define : + +.. coqtop:: all + + Inductive list2 (A:Set) : Set := + | nil2 : list2 A + | cons2 : A -> list2 (A*A) -> list2 A. + +that can also be written by specifying only the type of the arguments: + +.. coqtop:: all reset + + Inductive list2 (A:Set) : Set := nil2 | cons2 (_:A) (_:list2 (A*A)). + +But the following definition will give an error: + +.. coqtop:: all + + Fail Inductive listw (A:Set) : Set := + | nilw : listw (A*A) + | consw : A -> listw (A*A) -> listw (A*A). + +Because the conclusion of the type of constructors should be :g:`listw A` in +both cases. + +A parametrized inductive definition can be defined using annotations +instead of parameters but it will sometimes give a different (bigger) +sort for the inductive definition and will produce a less convenient +rule for case elimination. + +See also Section :ref:`inductive-definitions` and the :tacn:`induction` +tactic. + +Mutually defined inductive types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The definition of a block of mutually inductive types has the form: + +.. cmdv:: Inductive @ident : @term := {? | } @ident : @type {* | @ident : @type } {* with @ident : @term := {? | } @ident : @type {* | @ident : @type }}. + +It has the same semantics as the above ``Inductive`` definition for each +:token:`ident` All :token:`ident` are simultaneously added to the environment. +Then well-typing of constructors can be checked. Each one of the :token:`ident` +can be used on its own. + +It is also possible to parametrize these inductive definitions. However, +parameters correspond to a local context in which the whole set of +inductive declarations is done. For this reason, the parameters must be +strictly the same for each inductive types The extended syntax is: + +.. cmdv:: Inductive @ident {+ @binder} : @term := {? | } @ident : @type {* | @ident : @type } {* with @ident {+ @binder} : @term := {? | } @ident : @type {* | @ident : @type }}. + +The typical example of a mutual inductive data type is the one for trees and +forests. We assume given two types :g:`A` and :g:`B` as variables. It can +be declared the following way. + +.. coqtop:: in + + Variables A B : Set. + + Inductive tree : Set := + node : A -> forest -> tree + + with forest : Set := + | leaf : B -> forest + | cons : tree -> forest -> forest. + +This declaration generates automatically six induction principles. They are +respectively called :g:`tree_rec`, :g:`tree_ind`, :g:`tree_rect`, +:g:`forest_rec`, :g:`forest_ind`, :g:`forest_rect`. These ones are not the most +general ones but are just the induction principles corresponding to each +inductive part seen as a single inductive definition. + +To illustrate this point on our example, we give the types of :g:`tree_rec` +and :g:`forest_rec`. + +.. coqtop:: all + + Check tree_rec. + + Check forest_rec. + +Assume we want to parametrize our mutual inductive definitions with the +two type variables :g:`A` and :g:`B`, the declaration should be +done the following way: + +.. coqtop:: in + + Inductive tree (A B:Set) : Set := + node : A -> forest A B -> tree A B + + with forest (A B:Set) : Set := + | leaf : B -> forest A B + | cons : tree A B -> forest A B -> forest A B. + +Assume we define an inductive definition inside a section. When the +section is closed, the variables declared in the section and occurring +free in the declaration are added as parameters to the inductive +definition. + +See also Section :ref:`section-mechanism`. + +.. _coinductive-types: + +Co-inductive types +~~~~~~~~~~~~~~~~~~ + +The objects of an inductive type are well-founded with respect to the +constructors of the type. In other words, such objects contain only a +*finite* number of constructors. Co-inductive types arise from relaxing +this condition, and admitting types whose objects contain an infinity of +constructors. Infinite objects are introduced by a non-ending (but +effective) process of construction, defined in terms of the constructors +of the type. + +An example of a co-inductive type is the type of infinite sequences of +natural numbers, usually called streams. It can be introduced in +Coq using the ``CoInductive`` command: + +.. coqtop:: all + + CoInductive Stream : Set := + Seq : nat -> Stream -> Stream. + +The syntax of this command is the same as the command :cmd:`Inductive`. Notice +that no principle of induction is derived from the definition of a co-inductive +type, since such principles only make sense for inductive ones. For co-inductive +ones, the only elimination principle is case analysis. For example, the usual +destructors on streams :g:`hd:Stream->nat` and :g:`tl:Str->Str` can be defined +as follows: + +.. coqtop:: all + + Definition hd (x:Stream) := let (a,s) := x in a. + Definition tl (x:Stream) := let (a,s) := x in s. + +Definition of co-inductive predicates and blocks of mutually +co-inductive definitions are also allowed. An example of a co-inductive +predicate is the extensional equality on streams: + +.. coqtop:: all + + CoInductive EqSt : Stream -> Stream -> Prop := + eqst : forall s1 s2:Stream, + hd s1 = hd s2 -> EqSt (tl s1) (tl s2) -> EqSt s1 s2. + +In order to prove the extensionally equality of two streams :g:`s1` and :g:`s2` +we have to construct an infinite proof of equality, that is, an infinite object +of type :g:`(EqSt s1 s2)`. We will see how to introduce infinite objects in +Section :ref:`cofixpoint`. + +Definition of recursive functions +--------------------------------- + +Definition of functions by recursion over inductive objects +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This section describes the primitive form of definition by recursion over +inductive objects. See the :cmd:`Function` command for more advanced +constructions. + +.. _Fixpoint: + +.. cmd:: Fixpoint @ident @params {struct @ident} : @type := @term. + +This command allows defining functions by pattern-matching over inductive objects +using a fixed point construction. The meaning of this declaration is to +define :token:`ident` a recursive function with arguments specified by the +binders in :token:`params` such that :token:`ident` applied to arguments corresponding +to these binders has type :token:`type`:math:`_0`, and is equivalent to the +expression :token:`term`:math:`_0`. The type of the :token:`ident` is consequently +:g:`forall` :token:`params`, :token:`type`:math:`_0` and the value is equivalent to +:g:`fun` :token:`params` :g:`=>` :token:`term`:math:`_0`. + +To be accepted, a ``Fixpoint`` definition has to satisfy some syntactical +constraints on a special argument called the decreasing argument. They +are needed to ensure that the Fixpoint definition always terminates. The +point of the {struct :token:`ident`} annotation is to let the user tell the +system which argument decreases along the recursive calls. For instance, +one can define the addition function as : + +.. coqtop:: all + + Fixpoint add (n m:nat) {struct n} : nat := + match n with + | O => m + | S p => S (add p m) + end. + +The ``{struct`` :token:`ident```}`` annotation may be left implicit, in this case the +system try successively arguments from left to right until it finds one that +satisfies the decreasing condition. + +.. note:: + + Some fixpoints may have several arguments that fit as decreasing + arguments, and this choice influences the reduction of the fixpoint. Hence an + explicit annotation must be used if the leftmost decreasing argument is not the + desired one. Writing explicit annotations can also speed up type-checking of + large mutual fixpoints. + +The match operator matches a value (here :g:`n`) with the various +constructors of its (inductive) type. The remaining arguments give the +respective values to be returned, as functions of the parameters of the +corresponding constructor. Thus here when :g:`n` equals :g:`O` we return +:g:`m`, and when :g:`n` equals :g:`(S p)` we return :g:`(S (add p m))`. + +The match operator is formally described in detail in Section +:ref:`match-construction`. +The system recognizes that in the inductive call :g:`(add p m)` the first +argument actually decreases because it is a *pattern variable* coming from +:g:`match n with`. + +.. example:: + + The following definition is not correct and generates an error message: + + .. coqtop:: all + + Fail Fixpoint wrongplus (n m:nat) {struct n} : nat := + match m with + | O => n + | S p => S (wrongplus n p) + end. + + because the declared decreasing argument n actually does not decrease in + the recursive call. The function computing the addition over the second + argument should rather be written: + + .. coqtop:: all + + Fixpoint plus (n m:nat) {struct m} : nat := + match m with + | O => n + | S p => S (plus n p) + end. + +.. example:: + + The ordinary match operation on natural numbers can be mimicked in the + following way. + + .. coqtop:: all + + Fixpoint nat_match + (C:Set) (f0:C) (fS:nat -> C -> C) (n:nat) {struct n} : C := + match n with + | O => f0 + | S p => fS p (nat_match C f0 fS p) + end. + +.. example:: + + The recursive call may not only be on direct subterms of the recursive + variable n but also on a deeper subterm and we can directly write the + function mod2 which gives the remainder modulo 2 of a natural number. + + .. coqtop:: all + + Fixpoint mod2 (n:nat) : nat := + match n with + | O => O + | S p => match p with + | O => S O + | S q => mod2 q + end + end. + +In order to keep the strong normalization property, the fixed point +reduction will only be performed when the argument in position of the +decreasing argument (which type should be in an inductive definition) +starts with a constructor. + +The ``Fixpoint`` construction enjoys also the with extension to define functions +over mutually defined inductive types or more generally any mutually recursive +definitions. + +.. cmdv:: Fixpoint @ident @params {struct @ident} : @type := @term {* with @ident {+ @params} : @type := @term}. + +allows to define simultaneously fixpoints. + +The size of trees and forests can be defined the following way: + +.. coqtop:: all + + Fixpoint tree_size (t:tree) : nat := + match t with + | node a f => S (forest_size f) + end + with forest_size (f:forest) : nat := + match f with + | leaf b => 1 + | cons t f' => (tree_size t + forest_size f') + end. + +A generic command Scheme is useful to build automatically various mutual +induction principles. It is described in Section +:ref:`proofschemes-induction-principles`. + +.. _cofixpoint: + +Definitions of recursive objects in co-inductive types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. cmd:: CoFixpoint @ident : @type := @term. + +introduces a method for constructing an infinite object of a coinductive +type. For example, the stream containing all natural numbers can be +introduced applying the following method to the number :g:`O` (see +Section :ref:`coinductive-types` for the definition of :g:`Stream`, :g:`hd` and +:g:`tl`): + +.. coqtop:: all + + CoFixpoint from (n:nat) : Stream := Seq n (from (S n)). + +Oppositely to recursive ones, there is no decreasing argument in a +co-recursive definition. To be admissible, a method of construction must +provide at least one extra constructor of the infinite object for each +iteration. A syntactical guard condition is imposed on co-recursive +definitions in order to ensure this: each recursive call in the +definition must be protected by at least one constructor, and only by +constructors. That is the case in the former definition, where the +single recursive call of :g:`from` is guarded by an application of +:g:`Seq`. On the contrary, the following recursive function does not +satisfy the guard condition: + +.. coqtop:: all + + Fail CoFixpoint filter (p:nat -> bool) (s:Stream) : Stream := + if p (hd s) then Seq (hd s) (filter p (tl s)) else filter p (tl s). + +The elimination of co-recursive definition is done lazily, i.e. the +definition is expanded only when it occurs at the head of an application +which is the argument of a case analysis expression. In any other +context, it is considered as a canonical expression which is completely +evaluated. We can test this using the command ``Eval``, which computes +the normal forms of a term: + +.. coqtop:: all + + Eval compute in (from 0). + Eval compute in (hd (from 0)). + Eval compute in (tl (from 0)). + +.. cmdv:: CoFixpoint @ident @params : @type := @term + + As for most constructions, arguments of co-fixpoints expressions + can be introduced before the :g:`:=` sign. + +.. cmdv:: CoFixpoint @ident : @type := @term {+ with @ident : @type := @term } + + As in the :cmd:`Fixpoint` command, it is possible to introduce a block of + mutually dependent methods. + +.. _Assertions: + +Assertions and proofs +--------------------- + +An assertion states a proposition (or a type) of which the proof (or an +inhabitant of the type) is interactively built using tactics. The interactive +proof mode is described in Chapter :ref:`proofhandling` and the tactics in +Chapter :ref:`Tactics`. The basic assertion command is: + +.. cmd:: Theorem @ident : @type. + +After the statement is asserted, Coq needs a proof. Once a proof of +:token:`type` under the assumptions represented by :token:`binders` is given and +validated, the proof is generalized into a proof of forall , :token:`type` and +the theorem is bound to the name :token:`ident` in the environment. + +.. exn:: The term @term has type @type which should be Set, Prop or Type + +.. exn:: @ident already exists + + The name you provided is already defined. You have then to choose + another name. + +.. cmdv:: Lemma @ident : @type. + +.. cmdv:: Remark @ident : @type. + +.. cmdv:: Fact @ident : @type. + +.. cmdv:: Corollary @ident : @type. + +.. cmdv:: Proposition @ident : @type. + + These commands are synonyms of ``Theorem`` :token:`ident` : :token:`type`. + +.. cmdv:: Theorem @ident : @type {* with @ident : @type}. + + This command is useful for theorems that are proved by simultaneous induction + over a mutually inductive assumption, or that assert mutually dependent + statements in some mutual co-inductive type. It is equivalent to + :cmd:`Fixpoint` or :cmd:`CoFixpoint` but using tactics to build the proof of + the statements (or the body of the specification, depending on the point of + view). The inductive or co-inductive types on which the induction or + coinduction has to be done is assumed to be non ambiguous and is guessed by + the system. + + Like in a ``Fixpoint`` or ``CoFixpoint`` definition, the induction hypotheses + have to be used on *structurally smaller* arguments (for a ``Fixpoint``) or + be *guarded by a constructor* (for a ``CoFixpoint``). The verification that + recursive proof arguments are correct is done only at the time of registering + the lemma in the environment. To know if the use of induction hypotheses is + correct at some time of the interactive development of a proof, use the + command :cmd:`Guarded`. + + The command can be used also with ``Lemma``, ``Remark``, etc. instead of + ``Theorem``. + +.. cmdv:: Definition @ident : @type. + + This allows defining a term of type :token:`type` using the proof editing + mode. It behaves as Theorem but is intended to be used in conjunction with + :cmd:`Defined` in order to define a constant of which the computational + behavior is relevant. + + The command can be used also with :cmd:`Example` instead of :cmd:`Definition`. + + See also :cmd:`Opaque`, :cmd:`Transparent`, :tacn:`unfold`. + +.. cmdv:: Let @ident : @type. + + Like Definition :token:`ident` : :token:`type`. except that the definition is + turned into a let-in definition generalized over the declarations depending + on it after closing the current section. + +.. cmdv:: Fixpoint @ident @binders with . + + This generalizes the syntax of Fixpoint so that one or more bodies + can be defined interactively using the proof editing mode (when a + body is omitted, its type is mandatory in the syntax). When the block + of proofs is completed, it is intended to be ended by Defined. + +.. cmdv:: CoFixpoint @ident with. + + This generalizes the syntax of CoFixpoint so that one or more bodies + can be defined interactively using the proof editing mode. + +.. cmd:: Proof. … Qed. + +A proof starts by the keyword Proof. Then Coq enters the proof editing mode +until the proof is completed. The proof editing mode essentially contains +tactics that are described in chapter :ref:`Tactics`. Besides tactics, there are +commands to manage the proof editing mode. They are described in Chapter +:ref:`proofhandling`. When the proof is completed it should be validated and +put in the environment using the keyword Qed. + +.. exn:: @ident already exists + +.. note:: + + #. Several statements can be simultaneously asserted. + + #. Not only other assertions but any vernacular command can be given + while in the process of proving a given assertion. In this case, the + command is understood as if it would have been given before the + statements still to be proved. + + #. Proof is recommended but can currently be omitted. On the opposite + side, Qed (or Defined, see below) is mandatory to validate a proof. + + #. Proofs ended by Qed are declared opaque. Their content cannot be + unfolded (see :ref:`performingcomputations`), thus + realizing some form of *proof-irrelevance*. To be able to unfold a + proof, the proof should be ended by Defined (see below). + +.. cmdv:: Proof. … Defined. + + Same as ``Proof. … Qed.`` but the proof is then declared transparent, + which means that its content can be explicitly used for + type-checking and that it can be unfolded in conversion tactics + (see :ref:`performingcomputations`, :cmd:`Opaque`, :cmd:`Transparent`). + +.. cmdv:: Proof. … Admitted. + + Turns the current asserted statement into an axiom and exits the proof mode. + +.. [1] + This is similar to the expression “*entry* :math:`\{` sep *entry* + :math:`\}`” in standard BNF, or “*entry* :math:`(` sep *entry* + :math:`)`\ \*” in the syntax of regular expressions. + +.. [2] + Except if the inductive type is empty in which case there is no + equation that can be used to infer the return type. diff --git a/doc/sphinx/practical-tools/coq-commands.rst b/doc/sphinx/practical-tools/coq-commands.rst index 1ff808894..93dcfca4b 100644 --- a/doc/sphinx/practical-tools/coq-commands.rst +++ b/doc/sphinx/practical-tools/coq-commands.rst @@ -16,6 +16,8 @@ The options are (basically) the same for the first two commands, and roughly described below. You can also look at the ``man`` pages of ``coqtop`` and ``coqc`` for more details. +.. _interactive-use: + Interactive use (coqtop) ------------------------ @@ -39,10 +41,12 @@ Batch compilation (coqc) The ``coqc`` command takes a name *file* as argument. Then it looks for a vernacular file named *file*.v, and tries to compile it into a -*file*.vo file (See :ref:`TODO-6.5`). Warning: The name *file* should be a -regular |Coq| identifier, as defined in Section :ref:'TODO-1.1'. It should contain -only letters, digits or underscores (_). For instance, ``/bar/foo/toto.v`` is valid, but -``/bar/foo/to-to.v`` is invalid. +*file*.vo file (See :ref:`compiled-files`). + +.. caution:: The name *file* should be a + regular |Coq| identifier, as defined in Section :ref:'TODO-1.1'. It should contain + only letters, digits or underscores (_). For instance, ``/bar/foo/toto.v`` is valid, but + ``/bar/foo/to-to.v`` is invalid. Customization at launch time @@ -63,6 +67,7 @@ This file may contain, for instance, ``Add LoadPath`` commands to add directories to the load path of |Coq|. It is possible to skip the loading of the resource file with the option ``-q``. +.. _customization-by-environment-variables: By environment variables ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -70,7 +75,7 @@ By environment variables Load path can be specified to the |Coq| system by setting up ``$COQPATH`` environment variable. It is a list of directories separated by ``:`` (``;`` on Windows). |Coq| will also honor ``$XDG_DATA_HOME`` and -``$XDG_DATA_DIRS`` (see Section :ref:`TODO-2.6.3`). +``$XDG_DATA_DIRS`` (see Section :ref:`libraries-and-filesystem`). Some |Coq| commands call other |Coq| commands. In this case, they look for the commands in directory specified by ``$COQBIN``. If this variable is @@ -84,6 +89,8 @@ list of assignments of the form ``name=``:n:``{*; attr}`` where ANSI escape code. The list of highlight tags can be retrieved with the ``-list-tags`` command-line option of ``coqtop``. +.. _command-line-options: + By command line options ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -91,25 +98,25 @@ The following command-line options are recognized by the commands ``coqc`` and ``coqtop``, unless stated otherwise: :-I *directory*, -include *directory*: Add physical path *directory* - to the OCaml loadpath. See also: :ref:`TODO-2.6.1` and the - command Declare ML Module Section :ref:`TODO-6.5`. + to the OCaml loadpath. See also: :ref:`names-of-libraries` and the + command Declare ML Module Section :ref:`compiled-files`. :-Q *directory* dirpath: Add physical path *directory* to the list of directories where |Coq| looks for a file and bind it to the the logical directory *dirpath*. The subdirectory structure of *directory* is recursively available from |Coq| using absolute names (extending the - dirpath prefix) (see Section :ref:`TODO-2.6.2`).Note that only those + dirpath prefix) (see Section :ref:`qualified-names`).Note that only those subdirectories and files which obey the lexical conventions of what is - an ident (see Section :ref:`TODO-1.1`) are taken into account. Conversely, the + an :n:`@ident` are taken into account. Conversely, the underlying file systems or operating systems may be more restrictive than |Coq|. While Linux’s ext4 file system supports any |Coq| recursive layout (within the limit of 255 bytes per file name), the default on NTFS (Windows) or HFS+ (MacOS X) file systems is on the contrary to disallow two files differing only in the case in the same directory. - See also: Section :ref:`TODO-2.6.1`. + See also: Section :ref:`names-of-libraries`. :-R *directory* dirpath: Do as -Q *directory* dirpath but make the subdirectory structure of *directory* recursively visible so that the recursive contents of physical *directory* is available from |Coq| using - short or partially qualified names. See also: Section :ref:`TODO-2.6.1`. + short or partially qualified names. See also: Section :ref:`names-of-libraries`. :-top dirpath: Set the toplevel module name to dirpath instead of Top. Not valid for `coqc` as the toplevel module name is inferred from the name of the output file. @@ -145,7 +152,7 @@ and ``coqtop``, unless stated otherwise: -compile-verbose. :-w (all|none|w₁,…,wₙ): Configure the display of warnings. This option expects all, none or a comma-separated list of warning names or - categories (see Section :ref:`TODO-6.9.3`). + categories (see Section :ref:`controlling-display`). :-color (on|off|auto): Enable or not the coloring of output of `coqtop`. Default is auto, meaning that `coqtop` dynamically decides, depending on whether the output channel supports ANSI escape sequences. @@ -170,7 +177,7 @@ and ``coqtop``, unless stated otherwise: :-compat *version*: Attempt to maintain some backward-compatibility with a previous version. :-dump-glob *file*: Dump references for global names in file *file* - (to be used by coqdoc, see :ref:`TODO-15.4`). By default, if *file.v* is being + (to be used by coqdoc, see :ref:`coqdoc`). By default, if *file.v* is being compiled, *file.glob* is used. :-no-glob: Disable the dumping of references for global names. :-image *file*: Set the binary image to be used by `coqc` to be *file* diff --git a/doc/sphinx/practical-tools/coqide.rst b/doc/sphinx/practical-tools/coqide.rst index a3b942628..f9903e610 100644 --- a/doc/sphinx/practical-tools/coqide.rst +++ b/doc/sphinx/practical-tools/coqide.rst @@ -75,7 +75,7 @@ There are two additional buttons for navigation within the running buffer. The "down" button with a line goes directly to the end; the "up" button with a line goes back to the beginning. The handling of errors when using the go-to-the-end button depends on whether |Coq| is running in asynchronous mode or not (see -Chapter :ref:`Asyncprocessing`). If it is not running in that mode, execution +Chapter :ref:`asynchronousandparallelproofprocessing`). If it is not running in that mode, execution stops as soon as an error is found. Otherwise, execution continues, and the error is marked with an underline in the error foreground color, with a background in the error background color (pink by default). The same @@ -90,10 +90,10 @@ There are other buttons on the |CoqIDE| toolbar: a button to save the running buffer; a button to close the current buffer (an "X"); buttons to switch among buffers (left and right arrows); an "information" button; and a "gears" button. -The "information" button is described in Section :ref:`sec:trytactics`. +The "information" button is described in Section :ref:`try-tactics-automatically`. The "gears" button submits proof terms to the |Coq| kernel for type-checking. -When |Coq| uses asynchronous processing (see Chapter :ref:`Asyncprocessing`), +When |Coq| uses asynchronous processing (see Chapter :ref:`asynchronousandparallelproofprocessing`), proofs may have been completed without kernel-checking of generated proof terms. The presence of unchecked proof terms is indicated by ``Qed`` statements that have a subdued *being-processed* color (light blue by default), rather than the @@ -150,8 +150,6 @@ arguments. Queries ------------ -.. _coqide_queryselected: - .. image:: ../_static/coqide-queries.png :alt: |CoqIDE| queries @@ -161,7 +159,7 @@ writing them in scripts, |CoqIDE| offers a *query pane*. The query pane can be displayed on demand by using the ``View`` menu, or using the shortcut ``F1``. Queries can also be performed by selecting a particular phrase, then choosing an item from the ``Queries`` menu. The response then appears in the message window. -Figure :ref:`fig:queryselected` shows the result after selecting of the phrase +The image above shows the result after selecting of the phrase ``Nat.mul`` in the script window, and choosing ``Print`` from the ``Queries`` menu. diff --git a/doc/sphinx/practical-tools/utilities.rst b/doc/sphinx/practical-tools/utilities.rst index 620c002ff..59867988a 100644 --- a/doc/sphinx/practical-tools/utilities.rst +++ b/doc/sphinx/practical-tools/utilities.rst @@ -33,6 +33,7 @@ For example, to statically link |L_tac|, you can just do: % ocamlfind ocamlopt -thread -rectypes -linkall -linkpkg \ -package coq.toplevel -package coq.ltac \ toplevel/coqtop\_bin.ml -o my\_toplevel.native + and similarly for other plugins. @@ -43,7 +44,7 @@ The majority of |Coq| projects are very similar: a collection of ``.v`` files and eventually some ``.ml`` ones (a |Coq| plugin). The main piece of metadata needed in order to build the project are the command line options to ``coqc`` (e.g. ``-R``, ``-I``, see also: Section -:ref:`bycommandline`). Collecting the list of files and options is the job +:ref:`command-line-options`). Collecting the list of files and options is the job of the ``_CoqProject`` file. A simple example of a ``_CoqProject`` file follows: @@ -59,7 +60,7 @@ A simple example of a ``_CoqProject`` file follows: src/qux_plugin.mlpack -Currently, both |CoqIDE| and |ProofGeneral| (version ≥ ``4.3pre``) +Currently, both |CoqIDE| and Proof-General (version ≥ ``4.3pre``) understand ``_CoqProject`` files and invoke |Coq| with the desired options. The ``coq_makefile`` utility can be used to set up a build infrastructure @@ -77,7 +78,7 @@ CoqMakefile is a generic makefile for ``GNU Make`` that provides targets to build the project (both ``.v`` and ``.ml*`` files), to install it system-wide in the ``coq-contrib`` directory (i.e. where |Coq| is installed) - as well as to invoke |coqdoc| to generate |HTML| documentation. + as well as to invoke coqdoc to generate HTML documentation. CoqMakefile.conf contains make variables assignments that reflect @@ -89,7 +90,7 @@ An optional file ``CoqMakefile.local`` can be provided by the user in order to extend ``CoqMakefile``. In particular one can declare custom actions to be performed before or after the build process. Similarly one can customize the install target or even provide new targets. Extension points are documented in -paragraph :ref:`coqmakefile:local`. +paragraph :ref:`coqmakefilelocal`. The extensions of the files listed in ``_CoqProject`` is used in order to decide how to build them. In particular: @@ -113,32 +114,38 @@ distinct plugins because of a clash in their auxiliary module names. .. _coqmakefilelocal: CoqMakefile.local -+++++++++++++++++ - - +~~~~~~~~~~~~~~~~~ The optional file ``CoqMakefile.local`` is included by the generated file ``CoqMakefile``. It can contain two kinds of directives. -Variable assignment - The variable must belong to the variables listed in the ``Parameters`` section of the generated makefile. - Here we describe only few of them. - :CAMLPKGS: - can be used to specify third party findlib packages, and is - passed to the OCaml compiler on building or linking of modules. Eg: - ``-package yojson``. - :CAMLFLAGS: - can be used to specify additional flags to the |OCaml| - compiler, like ``-bin-annot`` or ``-w``.... - :COQC, COQDEP, COQDOC: - can be set in order to use alternative binaries - (e.g. wrappers) - :COQ_SRC_SUBDIRS: can be extended by including other paths in which ``*.cm*`` files are searched. For example ``COQ\_SRC\_SUBDIRS+=user-contrib/Unicoq`` lets you build a plugin containing OCaml code that depends on the OCaml code of ``Unicoq``. - -Rule extension - The following makefile rules can be extended. - - .. example :: +**Variable assignment** + +The variable must belong to the variables listed in the ``Parameters`` +section of the generated makefile. +Here we describe only few of them. + +:CAMLPKGS: + can be used to specify third party findlib packages, and is + passed to the OCaml compiler on building or linking of modules. Eg: + ``-package yojson``. +:CAMLFLAGS: + can be used to specify additional flags to the |OCaml| + compiler, like ``-bin-annot`` or ``-w``.... +:COQC, COQDEP, COQDOC: + can be set in order to use alternative binaries + (e.g. wrappers) +:COQ_SRC_SUBDIRS: + can be extended by including other paths in which ``*.cm*`` files + are searched. For example ``COQ\_SRC\_SUBDIRS+=user-contrib/Unicoq`` + lets you build a plugin containing OCaml code that depends on the + OCaml code of ``Unicoq``. + +**Rule extension** + +The following makefile rules can be extended. + +.. example:: :: @@ -147,42 +154,41 @@ Rule extension install-extra:: cp ThisExtraFile /there/it/goes - ``pre-all::`` - run before the all target. One can use this to configure - the project, or initialize sub modules or check dependencies are met. +``pre-all::`` + run before the ``all`` target. One can use this to configure + the project, or initialize sub modules or check dependencies are met. - ``post-all::`` - run after the all target. One can use this to run a test - suite, or compile extracted code. +``post-all::`` + run after the ``all`` target. One can use this to run a test + suite, or compile extracted code. +``install-extra::`` + run after ``install``. One can use this to install extra files. - ``install-extra::`` - run after install. One can use this to install extra files. +``install-doc::`` + One can use this to install extra doc. - ``install-doc::`` - One can use this to install extra doc. +``uninstall::`` + \ - ``uninstall::`` - \ +``uninstall-doc::`` + \ - ``uninstall-doc::`` - \ +``clean::`` + \ - ``clean::`` - \ +``cleanall::`` + \ - ``cleanall::`` - \ +``archclean::`` + \ - ``archclean::`` - \ - - ``merlin-hook::`` - One can append lines to the generated .merlin file extending this - target. +``merlin-hook::`` + One can append lines to the generated ``.merlin`` file extending this + target. Timing targets and performance testing -++++++++++++++++++++++++++++++++++++++ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The generated ``Makefile`` supports the generation of two kinds of timing data: per-file build-times, and per-line times for an individual file. @@ -311,8 +317,8 @@ line timing data: + ``print-pretty-single-time-diff`` :: - print-pretty-single-time-diff BEFORE=path/to/file.v.before-timing AFTER=path/to/file.v.after-timing + this target will make a sorted table of the per-line timing differences between the timing logs in the ``BEFORE`` and ``AFTER`` files, display it, and save it to the file specified by the ``TIME_OF_PRETTY_BUILD_FILE`` variable, @@ -357,7 +363,7 @@ line timing data: Reusing/extending the generated Makefile -++++++++++++++++++++++++++++++++++++++++ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Including the generated makefile with an include directive is discouraged. The contents of this file, including variable names and @@ -400,8 +406,8 @@ have a generic target for invoking unknown targets. -Building a subset of the targets with -j -++++++++++++++++++++++++++++++++++++++++ +Building a subset of the targets with ``-j`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To build, say, two targets foo.vo and bar.vo in parallel one can use ``make only TGTS="foo.vo bar.vo" -j``. @@ -451,14 +457,16 @@ automatically compute the dependencies among the files part of the project. +.. _coqdoc: + Documenting |Coq| files with coqdoc ----------------------------------- -|coqdoc| is a documentation tool for the proof assistant |Coq|, similar to -``javadoc`` or ``ocamldoc``. The task of |coqdoc| is +coqdoc is a documentation tool for the proof assistant |Coq|, similar to +``javadoc`` or ``ocamldoc``. The task of coqdoc is -#. to produce a nice |Latex| and/or |HTML| document from the |Coq| +#. to produce a nice |Latex| and/or HTML document from the |Coq| sources, readable for a human and not only for the proof assistant; #. to help the user navigating in his own (or third-party) sources. @@ -468,18 +476,18 @@ Principles ~~~~~~~~~~ Documentation is inserted into |Coq| files as *special comments*. Thus -your files will compile as usual, whether you use |coqdoc| or not. |coqdoc| +your files will compile as usual, whether you use coqdoc or not. coqdoc presupposes that the given |Coq| files are well-formed (at least lexically). Documentation starts with ``(**``, followed by a space, and ends with the pending ``*)``. The documentation format is inspired by Todd A. Coram’s *Almost Free Text (AFT)* tool: it is mainly ``ASCII`` text with -some syntax-light controls, described below. |coqdoc| is robust: it +some syntax-light controls, described below. coqdoc is robust: it shouldn’t fail, whatever the input is. But remember: “garbage in, garbage out”. |Coq| material inside documentation. -++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ |Coq| material is quoted between the delimiters ``[`` and ``]``. Square brackets may be nested, the inner ones being understood as being part of the @@ -494,7 +502,7 @@ followed by a newline and the latter must follow a newline. Pretty-printing. ++++++++++++++++ -|coqdoc| uses different faces for identifiers and keywords. The pretty- +coqdoc uses different faces for identifiers and keywords. The pretty- printing of |Coq| tokens (identifiers or symbols) can be controlled using one of the following commands: @@ -512,8 +520,8 @@ or (** printing *token* $...LATEX math...$ #...html...# *) -It gives the |Latex| and |HTML| texts to be produced for the given |Coq| -token. One of the |Latex| or |HTML| text may be omitted, causing the +It gives the |Latex| and HTML texts to be produced for the given |Coq| +token. One of the |Latex| or HTML text may be omitted, causing the default pretty-printing to be used for this token. The printing for one token can be removed with @@ -530,27 +538,28 @@ Initially, the pretty-printing table contains the following mapping: `->` → `<-` ← `*` × `<=` ≤ `>=` ≥ `=>` ⇒ `<>` ≠ `<->` ↔ `|-` ⊢ -`\/` ∨ `/\` ∧ `~` ¬ +`\/` ∨ `/\\` ∧ `~` ¬ ==== === ==== ===== === ==== ==== === Any of these can be overwritten or suppressed using the printing commands. -.. note :: - The recognition of tokens is done by a (``ocaml``) lex - automaton and thus applies the longest-match rule. For instance, `->~` - is recognized as a single token, where |Coq| sees two tokens. It is the - responsibility of the user to insert space between tokens *or* to give - pretty-printing rules for the possible combinations, e.g. +.. note:: + + The recognition of tokens is done by a (``ocaml``) lex + automaton and thus applies the longest-match rule. For instance, `->~` + is recognized as a single token, where |Coq| sees two tokens. It is the + responsibility of the user to insert space between tokens *or* to give + pretty-printing rules for the possible combinations, e.g. - :: + :: (** printing ->~ %\ensuremath{\rightarrow\lnot}% *) -Sections. -+++++++++ +Sections +++++++++ Sections are introduced by 1 to 4 leading stars (i.e. at the beginning of the line) followed by a space. One star is a section, two stars a @@ -559,7 +568,7 @@ line. .. example:: - :: + :: (** * Well-founded relations @@ -614,18 +623,18 @@ emphasis. Usually, these are spaces or punctuation. -Escaping to |Latex| and |HTML|. +Escaping to |Latex| and HTML. +++++++++++++++++++++++++++++++ -Pure |Latex| or |HTML| material can be inserted using the following +Pure |Latex| or HTML material can be inserted using the following escape sequences: + ``$...LATEX stuff...$`` inserts some |Latex| material in math mode. - Simply discarded in |HTML| output. + Simply discarded in HTML output. + ``%...LATEX stuff...%`` inserts some |Latex| material. Simply - discarded in |HTML| output. -+ ``#...HTML stuff...#`` inserts some |HTML| material. Simply discarded in + discarded in HTML output. ++ ``#...HTML stuff...#`` inserts some HTML material. Simply discarded in |Latex| output. .. note:: @@ -654,7 +663,7 @@ at the beginning of a line. Hyperlinks ++++++++++ -Hyperlinks can be inserted into the |HTML| output, so that any +Hyperlinks can be inserted into the HTML output, so that any identifier is linked to the place of its definition. ``coqc file.v`` automatically dumps localization information in @@ -662,7 +671,7 @@ identifier is linked to the place of its definition. file``. Take care of erasing this global file, if any, when starting the whole compilation process. -Then invoke |coqdoc| or ``coqdoc --glob-from file`` to tell |coqdoc| to look +Then invoke coqdoc or ``coqdoc --glob-from file`` to tell coqdoc to look for name resolutions into the file ``file`` (it will look in ``file.glob`` by default). @@ -703,17 +712,17 @@ be used around a whole proof. Usage ~~~~~ -|coqdoc| is invoked on a shell command line as follows: +coqdoc is invoked on a shell command line as follows: ``coqdoc <options and files>``. Any command line argument which is not an option is considered to be a file (even if it starts with a ``-``). |Coq| files are identified by the suffixes ``.v`` and ``.g`` and |Latex| files by the suffix ``.tex``. -:|HTML| output: This is the default output. One |HTML| file is created for +:HTML output: This is the default output. One HTML file is created for each |Coq| file given on the command line, together with a file - ``index.html`` (unless ``option-no-index is passed``). The |HTML| pages use a - style sheet named ``style.css``. Such a file is distributed with |coqdoc|. + ``index.html`` (unless ``option-no-index is passed``). The HTML pages use a + style sheet named ``style.css``. Such a file is distributed with coqdoc. :|Latex| output: A single |Latex| file is created, on standard output. It can be redirected to a file with option ``-o``. The order of files on the command line is kept in the final document. |Latex| @@ -732,7 +741,7 @@ Command line options **Overall options** - :--|HTML|: Select a |HTML| output. + :--HTML: Select a HTML output. :--|Latex|: Select a |Latex| output. :--dvi: Select a DVI output. :--ps: Select a PostScript output. @@ -760,7 +769,7 @@ Command line options **Index options** - Default behavior is to build an index, for the |HTML| output only, + Default behavior is to build an index, for the HTML output only, into ``index.html``. :--no-index: Do not output the index. @@ -775,7 +784,7 @@ Command line options :-toc, --table-of-contents: Insert a table of contents. For a |Latex| output, it inserts a ``\tableofcontents`` at the beginning of the - document. For a |HTML| output, it builds a table of contents into + document. For a HTML output, it builds a table of contents into ``toc.html``. :--toc-depth int: Only include headers up to depth ``int`` in the table of contents. @@ -795,28 +804,28 @@ Command line options directory ``coqdir`` (similarly to |Coq| option ``-R``). .. note:: - option ``-R`` only has - effect on the files *following* it on the command line, so you will - probably need to put this option first. + + option ``-R`` only has + effect on the files *following* it on the command line, so you will + probably need to put this option first. **Title options** :-s , --short: Do not insert titles for the files. The default - behavior is to insert a title like “Library Foo” for each file. + behavior is to insert a title like “Library Foo” for each file. :--lib-name string: Print “string Foo” instead of “Library Foo” in - titles. For example “Chapter” and “Module” are reasonable choices. + titles. For example “Chapter” and “Module” are reasonable choices. :--no-lib-name: Print just “Foo” instead of “Library Foo” in titles. :--lib-subtitles: Look for library subtitles. When enabled, the - beginning of each file is checked for a comment of the form: - - :: + beginning of each file is checked for a comment of the form: + :: - (** * ModuleName : text *) + (** * ModuleName : text *) - where ``ModuleName`` must be the name of the file. If it is present, the - text is used as a subtitle for the module in appropriate places. + where ``ModuleName`` must be the name of the file. If it is present, the + text is used as a subtitle for the module in appropriate places. :-t string, --title string: Set the document title. @@ -854,11 +863,11 @@ Command line options :-latin1, --latin1: Select ISO-8859-1 input files. It is equivalent to --inputenc latin1 --charset iso-8859-1. :-utf8, --utf8: Set --inputenc utf8x for |Latex| output and--charset - utf-8 for |HTML| output. Also use Unicode replacements for a couple of + utf-8 for HTML output. Also use Unicode replacements for a couple of standard plain ASCII notations such as → for ``->`` and ∀ for ``forall``. |Latex| UTF-8 support can be found at `<http://www.ctan.org/pkg/unicode>`_. For the interpretation of Unicode - characters by |Latex|, extra packages which |coqdoc| does not provide + characters by |Latex|, extra packages which coqdoc does not provide by default might be required, such as textgreek for some Greek letters or ``stmaryrd`` for some mathematical symbols. If a Unicode character is missing an interpretation in the utf8x input encoding, add @@ -866,13 +875,13 @@ Command line options and declarations can be added with option ``-p``. :--inputenc string: Give a |Latex| input encoding, as an option to |Latex| package ``inputenc``. - :--charset string: Specify the |HTML| character set, to be inserted in - the |HTML| header. + :--charset string: Specify the HTML character set, to be inserted in + the HTML header. The coqdoc |Latex| style file -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In case you choose to produce a document without the default |Latex| preamble (by using option ``--no-preamble``), then you must insert into @@ -929,16 +938,16 @@ There are options to produce the |Coq| parts in smaller font, italic, between horizontal rules, etc. See the man page of ``coq-tex`` for more details. -|Coq| and |GNU| |Emacs| +|Coq| and GNU Emacs ----------------------- -The |Coq| |Emacs| mode +The |Coq| Emacs mode ~~~~~~~~~~~~~~~~~~~~~~~~~ -|Coq| comes with a Major mode for |GNU| |Emacs|, ``gallina.el``. This mode +|Coq| comes with a Major mode for GNU Emacs, ``gallina.el``. This mode provides syntax highlighting and also a rudimentary indentation -facility in the style of the ``Caml`` |GNU| |Emacs| mode. +facility in the style of the ``Caml`` GNU Emacs mode. Add the following lines to your ``.emacs`` file: @@ -956,26 +965,26 @@ facility: + pressing ``Tab`` at the beginning of a line indents the line like the line above; -+ extra ``Tab``s increase the indentation level (by 2 spaces by default); ++ extra tabulations increase the indentation level (by 2 spaces by default); + ``M-Tab`` decreases the indentation level. -An inferior mode to run |Coq| under |Emacs|, by Marco Maggesi, is also +An inferior mode to run |Coq| under Emacs, by Marco Maggesi, is also included in the distribution, in file ``inferior-coq.el``. Instructions to use it are contained in this file. -Proof General +Proof-General ~~~~~~~~~~~~~ -|ProofGeneral| is a generic interface for proof assistants based on -|Emacs|. The main idea is that the |Coq| commands you are editing are sent -to a |Coq| toplevel running behind |Emacs| and the answers of the system -automatically inserted into other |Emacs| buffers. Thus you don’t need +Proof-General is a generic interface for proof assistants based on +Emacs. The main idea is that the |Coq| commands you are editing are sent +to a |Coq| toplevel running behind Emacs and the answers of the system +automatically inserted into other Emacs buffers. Thus you don’t need to copy-paste the |Coq| material from your files to the |Coq| toplevel or conversely from the |Coq| toplevel to some files. -|ProofGeneral| is developed and distributed independently of the system +Proof-General is developed and distributed independently of the system |Coq|. It is freely available at `<https://proofgeneral.github.io/>`_. diff --git a/doc/sphinx/proof-engine/detailed-tactic-examples.rst b/doc/sphinx/proof-engine/detailed-tactic-examples.rst index 932f96788..84810ddba 100644 --- a/doc/sphinx/proof-engine/detailed-tactic-examples.rst +++ b/doc/sphinx/proof-engine/detailed-tactic-examples.rst @@ -6,6 +6,8 @@ Detailed examples of tactics This chapter presents detailed examples of certain tactics, to illustrate their behavior. +.. _dependent-induction: + dependent induction ------------------- @@ -316,7 +318,7 @@ explicit proof terms: This concludes our example. -See also: The ``induction`` :ref:`TODO-9-induction`, ``case`` :ref:`TODO-9-induction` and ``inversion`` :ref:`TODO-8.14-inversion` tactics. +See also: The :tacn:`induction`, :tacn:`case`, and :tacn:`inversion` tactics. autorewrite @@ -403,6 +405,8 @@ Example 2: Mac Carthy function autorewrite with base1 using reflexivity || simpl. +.. _quote: + quote ----- @@ -544,8 +548,7 @@ Combining variables and constants ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ One can have both variables and constants in abstracts terms; for -example, this is the case for the ``ring`` tactic -:ref:`TODO-25-ringandfieldtacticfamilies`. Then one must provide to +example, this is the case for the :tacn:`ring` tactic. 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. @@ -606,7 +609,7 @@ don’t expect miracles from it! See also: comments of source file ``plugins/quote/quote.ml`` -See also: the ``ring`` tactic :ref:`TODO-25-ringandfieldtacticfamilies` +See also: the :tacn:`ring` tactic. Using the tactical language @@ -733,7 +736,7 @@ and this length is decremented for each rotation down to, but not including, 1 because for a list of length ``n``, we can make exactly ``n−1`` rotations to generate at most ``n`` distinct lists. Here, it must be noticed that we use the natural numbers of Coq for the -rotation counter. On Figure :ref:`TODO-9.1-tactic-language`, we can +rotation counter. In :ref:`ltac-syntax`, we can see that it is possible to use usual natural numbers but they are only used as arguments for primitive tactics and they cannot be handled, in particular, we cannot make computations with them. So, a natural @@ -830,7 +833,7 @@ The pattern matching on goals allows a complete and so a powerful backtracking when returning tactic values. An interesting application is the problem of deciding intuitionistic propositional logic. Considering the contraction-free sequent calculi LJT* of Roy Dyckhoff -:ref:`TODO-56-biblio`, it is quite natural to code such a tactic +:cite:`Dyc92`, it is quite natural to code such a tactic using the tactic language as shown on figures: :ref:`Deciding intuitionistic propositions (1) <decidingintuitionistic1>` and :ref:`Deciding intuitionistic propositions (2) @@ -868,7 +871,7 @@ Deciding type isomorphisms A more tricky problem is to decide equalities between types and modulo isomorphisms. Here, we choose to use the isomorphisms of the simply typed λ-calculus with Cartesian product and unit type (see, for -example, [:ref:`TODO-45`]). The axioms of this λ-calculus are given below. +example, :cite:`RC95`). The axioms of this λ-calculus are given below. .. coqtop:: in reset diff --git a/doc/sphinx/proof-engine/ltac.rst b/doc/sphinx/proof-engine/ltac.rst new file mode 100644 index 000000000..247d5d899 --- /dev/null +++ b/doc/sphinx/proof-engine/ltac.rst @@ -0,0 +1,1267 @@ +.. include:: ../preamble.rst +.. include:: ../replaces.rst + +.. _ltac: + +The tactic language +=================== + +This chapter gives a compact documentation of |Ltac|, the tactic language +available in |Coq|. We start by giving the syntax, and next, we present the +informal semantics. If you want to know more regarding this language and +especially about its foundations, you can refer to :cite:`Del00`. Chapter +:ref:`detailedexamplesoftactics` is devoted to giving examples of use of this +language on small but also with non-trivial problems. + +.. _ltac-syntax: + +Syntax +------ + +The syntax of the tactic language is given below. See Chapter +:ref:`gallinaspecificationlanguage` for a description of the BNF metasyntax used +in these grammar rules. Various already defined entries will be used in this +chapter: entries :token:`natural`, :token:`integer`, :token:`ident`, +:token:`qualid`, :token:`term`, :token:`cpattern` and :token:`atomic_tactic` +represent respectively the natural and integer numbers, the authorized +identificators and qualified names, Coq terms and patterns and all the atomic +tactics described in Chapter :ref:`tactics`. The syntax of :token:`cpattern` is +the same as that of terms, but it is extended with pattern matching +metavariables. In :token:`cpattern`, a pattern-matching metavariable is +represented with the syntax :g:`?id` where :g:`id` is an :token:`ident`. The +notation :g:`_` can also be used to denote metavariable whose instance is +irrelevant. In the notation :g:`?id`, the identifier allows us to keep +instantiations and to make constraints whereas :g:`_` shows that we are not +interested in what will be matched. On the right hand side of pattern-matching +clauses, the named metavariable are used without the question mark prefix. There +is also a special notation for second-order pattern-matching problems: in an +applicative pattern of the form :g:`@?id id1 … idn`, the variable id matches any +complex expression with (possible) dependencies in the variables :g:`id1 … idn` +and returns a functional term of the form :g:`fun id1 … idn => term`. + +The main entry of the grammar is :n:`@expr`. This language is used in proof +mode but it can also be used in toplevel definitions as shown below. + +.. note:: + + - The infix tacticals “… \|\| …”, “… + …”, and “… ; …” are associative. + + - In :token:`tacarg`, there is an overlap between qualid as a direct tactic + argument and :token:`qualid` as a particular case of term. The resolution is + done by first looking for a reference of the tactic language and if + it fails, for a reference to a term. To force the resolution as a + reference of the tactic language, use the form :g:`ltac:(@qualid)`. To + force the resolution as a reference to a term, use the syntax + :g:`(@qualid)`. + + - As shown by the figure, tactical ``\|\|`` binds more than the prefix + tacticals try, repeat, do and abstract which themselves bind more + than the postfix tactical “… ;[ … ]” which binds more than “… ; …”. + + For instance + + .. coqtop:: in + + try repeat tac1 || tac2; tac3; [tac31 | ... | tac3n]; tac4. + + is understood as + + .. coqtop:: in + + try (repeat (tac1 || tac2)); + ((tac3; [tac31 | ... | tac3n]); tac4). + +.. productionlist:: coq + expr : `expr` ; `expr` + : | [> `expr` | ... | `expr` ] + : | `expr` ; [ `expr` | ... | `expr` ] + : | `tacexpr3` + tacexpr3 : do (`natural` | `ident`) tacexpr3 + : | progress `tacexpr3` + : | repeat `tacexpr3` + : | try `tacexpr3` + : | once `tacexpr3` + : | exactly_once `tacexpr3` + : | timeout (`natural` | `ident`) `tacexpr3` + : | time [`string`] `tacexpr3` + : | only `selector`: `tacexpr3` + : | `tacexpr2` + tacexpr2 : `tacexpr1` || `tacexpr3` + : | `tacexpr1` + `tacexpr3` + : | tryif `tacexpr1` then `tacexpr1` else `tacexpr1` + : | `tacexpr1` + tacexpr1 : fun `name` ... `name` => `atom` + : | let [rec] `let_clause` with ... with `let_clause` in `atom` + : | match goal with `context_rule` | ... | `context_rule` end + : | match reverse goal with `context_rule` | ... | `context_rule` end + : | match `expr` with `match_rule` | ... | `match_rule` end + : | lazymatch goal with `context_rule` | ... | `context_rule` end + : | lazymatch reverse goal with `context_rule` | ... | `context_rule` end + : | lazymatch `expr` with `match_rule` | ... | `match_rule` end + : | multimatch goal with `context_rule` | ... | `context_rule` end + : | multimatch reverse goal with `context_rule` | ... | `context_rule` end + : | multimatch `expr` with `match_rule` | ... | `match_rule` end + : | abstract `atom` + : | abstract `atom` using `ident` + : | first [ `expr` | ... | `expr` ] + : | solve [ `expr` | ... | `expr` ] + : | idtac [ `message_token` ... `message_token`] + : | fail [`natural`] [`message_token` ... `message_token`] + : | fresh | fresh `string` | fresh `qualid` + : | context `ident` [`term`] + : | eval `redexpr` in `term` + : | type of `term` + : | constr : `term` + : | uconstr : `term` + : | type_term `term` + : | numgoals + : | guard `test` + : | assert_fails `tacexpr3` + : | assert_suceeds `tacexpr3` + : | `atomic_tactic` + : | `qualid` `tacarg` ... `tacarg` + : | `atom` + atom : `qualid` + : | () + : | `integer` + : | ( `expr` ) + message_token : `string` | `ident` | `integer` + tacarg : `qualid` + : | () + : | ltac : `atom` + : | `term` + let_clause : `ident` [`name` ... `name`] := `expr` + context_rule : `context_hyp`, ..., `context_hyp` |- `cpattern` => `expr` + : | `cpattern` => `expr` + : | |- `cpattern` => `expr` + : | _ => `expr` + context_hyp : `name` : `cpattern` + : | `name` := `cpattern` [: `cpattern`] + match_rule : `cpattern` => `expr` + : | context [ident] [ `cpattern` ] => `expr` + : | _ => `expr` + test : `integer` = `integer` + : | `integer` (< | <= | > | >=) `integer` + selector : [`ident`] + : | `integer` + : (`integer` | `integer` - `integer`), ..., (`integer` | `integer` - `integer`) + toplevel_selector : `selector` + : | `all` + : | `par` + +.. productionlist:: coq + top : [Local] Ltac `ltac_def` with ... with `ltac_def` + ltac_def : `ident` [`ident` ... `ident`] := `expr` + : | `qualid` [`ident` ... `ident`] ::= `expr` + +.. _ltac-semantics: + +Semantics +--------- + +Tactic expressions can only be applied in the context of a proof. The +evaluation yields either a term, an integer or a tactic. Intermediary +results can be terms or integers but the final result must be a tactic +which is then applied to the focused goals. + +There is a special case for ``match goal`` expressions of which the clauses +evaluate to tactics. Such expressions can only be used as end result of +a tactic expression (never as argument of a non recursive local +definition or of an application). + +The rest of this section explains the semantics of every construction of +|Ltac|. + +Sequence +~~~~~~~~ + +A sequence is an expression of the following form: + +.. tacn:: @expr ; @expr + + The expression :n:`@expr__1` is evaluated to :n:`v__1`, which must be + a tactic value. The tactic :n:`v__1` is applied to the current goal, + possibly producing more goals. Then :n:`@expr__2` is evaluated to + produce :n:`v__2`, which must be a tactic value. The tactic + :n:`v__2` is applied to all the goals produced by the prior + application. Sequence is associative. + +Local application of tactics +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Different tactics can be applied to the different goals using the +following form: + +.. tacn:: [> {*| @expr }] + + The expressions :n:`@expr__i` are evaluated to :n:`v__i`, for + i=0,...,n and all have to be tactics. The :n:`v__i` is applied to the + i-th goal, for =1,...,n. It fails if the number of focused goals is not + exactly n. + + .. note:: + + If no tactic is given for the i-th goal, it behaves as if the tactic idtac + were given. For instance, ``[> | auto]`` is a shortcut for ``[> idtac | auto + ]``. + + .. tacv:: [> {*| @expr} | @expr .. | {*| @expr}] + + In this variant, token:`expr` is used for each goal coming after those + covered by the first list of :n:`@expr` but before those coevered by the + last list of :n:`@expr`. + + .. tacv:: [> {*| @expr} | .. | {*| @expr}] + + In this variant, idtac is used for the goals not covered by the two lists of + :n:`@expr`. + + .. tacv:: [> @expr .. ] + + In this variant, the tactic :n:`@expr` is applied independently to each of + the goals, rather than globally. In particular, if there are no goal, the + tactic is not run at all. A tactic which expects multiple goals, such as + ``swap``, would act as if a single goal is focused. + + .. tacv:: expr ; [{*| @expr}] + + This variant of local tactic application is paired with a sequence. In this + variant, there must be as many :n:`@expr` in the list as goals generated + by the application of the first :n:`@expr` to each of the individual goals + independently. All the above variants work in this form too. + Formally, :n:`@expr ; [ ... ]` is equivalent to :n:`[> @expr ; [> ... ] .. ]`. + +.. _goal-selectors: + +Goal selectors +~~~~~~~~~~~~~~ + +We can restrict the application of a tactic to a subset of the currently +focused goals with: + +.. tacn:: @toplevel_selector : @expr + + We can also use selectors as a tactical, which allows to use them nested + in a tactic expression, by using the keyword ``only``: + + .. tacv:: only selector : expr + + When selecting several goals, the tactic expr is applied globally to all + selected goals. + + .. tacv:: [@ident] : @expr + + In this variant, :n:`@expr` is applied locally to a goal previously named + by the user (see :ref:`existential-variables`). + + .. tacv:: @num : @expr + + In this variant, :n:`@expr` is applied locally to the :token:`num`-th goal. + + .. tacv:: {+, @num-@num} : @expr + + In this variant, :n:`@expr` is applied globally to the subset of goals + described by the given ranges. You can write a single ``n`` as a shortcut + for ``n-n`` when specifying multiple ranges. + + .. tacv:: all: @expr + + In this variant, :n:`@expr` is applied to all focused goals. ``all:`` can only + be used at the toplevel of a tactic expression. + + .. tacv:: par: @expr + + In this variant, :n:`@expr` is applied to all focused goals in parallel. + The number of workers can be controlled via the command line option + ``-async-proofs-tac-j`` taking as argument the desired number of workers. + Limitations: ``par:`` only works on goals containing no existential + variables and :n:`@expr` must either solve the goal completely or do + nothing (i.e. it cannot make some progress). ``par:`` can only be used at + the toplevel of a tactic expression. + + .. exn:: No such goal + :name: No such goal (goal selector) + + .. TODO change error message index entry + +For loop +~~~~~~~~ + +There is a for loop that repeats a tactic :token:`num` times: + +.. tacn:: do @num @expr + + :n:`@expr` is evaluated to ``v`` which must be a tactic value. This tactic + value ``v`` is applied :token:`num` times. Supposing :token:`num` > 1, after the + first application of ``v``, ``v`` is applied, at least once, to the generated + subgoals and so on. It fails if the application of ``v`` fails before the num + applications have been completed. + +Repeat loop +~~~~~~~~~~~ + +We have a repeat loop with: + +.. tacn:: repeat @expr + + :n:`@expr` is evaluated to ``v``. If ``v`` denotes a tactic, this tactic is + applied to each focused goal independently. If the application succeeds, the + tactic is applied recursively to all the generated subgoals until it eventually + fails. The recursion stops in a subgoal when the tactic has failed *to make + progress*. The tactic :n:`repeat @expr` itself never fails. + +Error catching +~~~~~~~~~~~~~~ + +We can catch the tactic errors with: + +.. tacn:: try @expr + + :n:`@expr` is evaluated to ``v`` which must be a tactic value. The tactic + value ``v`` is applied to each focused goal independently. If the application of + ``v`` fails in a goal, it catches the error and leaves the goal unchanged. If the + level of the exception is positive, then the exception is re-raised with its + level decremented. + +Detecting progress +~~~~~~~~~~~~~~~~~~ + +We can check if a tactic made progress with: + +.. tacn:: progress expr + + :n:`@expr` is evaluated to v which must be a tactic value. The tactic value ``v`` + is applied to each focued subgoal independently. If the application of ``v`` + to one of the focused subgoal produced subgoals equal to the initial + goals (up to syntactical equality), then an error of level 0 is raised. + + .. exn:: Failed to progress + +Backtracking branching +~~~~~~~~~~~~~~~~~~~~~~ + +We can branch with the following structure: + +.. tacn:: @expr__1 + @expr__2 + + :n:`@expr__1` and :n:`@expr__2` are evaluated respectively to :n:`v__1` and + :n:`v__2` which must be tactic values. The tactic value :n:`v__1` is applied to + each focused goal independently and if it fails or a later tactic fails, then + the proof backtracks to the current goal and :n:`v__2` is applied. + + Tactics can be seen as having several successes. When a tactic fails it + asks for more successes of the prior tactics. + :n:`@expr__1 + @expr__2` has all the successes of :n:`v__1` followed by all the + successes of :n:`v__2`. Algebraically, + :n:`(@expr__1 + @expr__2); @expr__3 = (@expr__1; @expr__3) + (@expr__2; @expr__3)`. + + Branching is left-associative. + +First tactic to work +~~~~~~~~~~~~~~~~~~~~ + +Backtracking branching may be too expensive. In this case we may +restrict to a local, left biased, branching and consider the first +tactic to work (i.e. which does not fail) among a panel of tactics: + +.. tacn:: first [{*| @expr}] + + The :n:`@expr__i` are evaluated to :n:`v__i` and :n:`v__i` must be + tactic values, for i=1,...,n. Supposing n>1, it applies, in each focused + goal independently, :n:`v__1`, if it works, it stops otherwise it + tries to apply :n:`v__2` and so on. It fails when there is no + applicable tactic. In other words, + :n:`first [:@expr__1 | ... | @expr__n]` behaves, in each goal, as the the first + :n:`v__i` to have *at least* one success. + + .. exn:: Error message: No applicable tactic + + .. tacv:: first @expr + + This is an |Ltac| alias that gives a primitive access to the first + tactical as a |Ltac| definition without going through a parsing rule. It + expects to be given a list of tactics through a ``Tactic Notation``, + allowing to write notations of the following form: + + .. example:: + + .. coqtop:: in + + Tactic Notation "foo" tactic_list(tacs) := first tacs. + +Left-biased branching +~~~~~~~~~~~~~~~~~~~~~ + +Yet another way of branching without backtracking is the following +structure: + +.. tacn:: @expr__1 || @expr__2 + + :n:`@expr__1` and :n:`@expr__2` are evaluated respectively to :n:`v__1` and + :n:`v__2` which must be tactic values. The tactic value :n:`v__1` is + applied in each subgoal independently and if it fails *to progress* then + :n:`v__2` is applied. :n:`@expr__1 || @expr__2` is + equivalent to :n:`first [ progress @expr__1 | @expr__2 ]` (except that + if it fails, it fails like :n:`v__2`). Branching is left-associative. + +Generalized biased branching +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The tactic + +.. tacn:: tryif @expr__1 then @expr__2 else @expr__3 + + is a generalization of the biased-branching tactics above. The + expression :n:`@expr__1` is evaluated to :n:`v__1`, which is then + applied to each subgoal independently. For each goal where :n:`v__1` + succeeds at least once, :n:`@expr__2` is evaluated to :n:`v__2` which + is then applied collectively to the generated subgoals. The :n:`v__2` + tactic can trigger backtracking points in :n:`v__1`: where :n:`v__1` + succeeds at least once, + :n:`tryif @expr__1 then @expr__2 else @expr__3` is equivalent to + :n:`v__1; v__2`. In each of the goals where :n:`v__1` does not succeed at least + once, :n:`@expr__3` is evaluated in :n:`v__3` which is is then applied to the + goal. + +Soft cut +~~~~~~~~ + +Another way of restricting backtracking is to restrict a tactic to a +single success *a posteriori*: + +.. tacn:: once @expr + + :n:`@expr` is evaluated to ``v`` which must be a tactic value. The tactic value + ``v`` is applied but only its first success is used. If ``v`` fails, + :n:`once @expr` fails like ``v``. If ``v`` has a least one success, + :n:`once @expr` succeeds once, but cannot produce more successes. + +Checking the successes +~~~~~~~~~~~~~~~~~~~~~~ + +Coq provides an experimental way to check that a tactic has *exactly +one* success: + +.. tacn:: exactly_once @expr + + :n:`@expr` is evaluated to ``v`` which must be a tactic value. The tactic value + ``v`` is applied if it has at most one success. If ``v`` fails, + :n:`exactly_once @expr` fails like ``v``. If ``v`` has a exactly one success, + :n:`exactly_once @expr` succeeds like ``v``. If ``v`` has two or more + successes, exactly_once expr fails. + + .. warning:: + + The experimental status of this tactic pertains to the fact if ``v`` + performs side effects, they may occur in a unpredictable way. Indeed, + normally ``v`` would only be executed up to the first success until + backtracking is needed, however exactly_once needs to look ahead to see + whether a second success exists, and may run further effects + immediately. + + .. exn:: This tactic has more than one success + +Checking the failure +~~~~~~~~~~~~~~~~~~~~ + +Coq provides a derived tactic to check that a tactic *fails*: + +.. tacn:: assert_fails @expr + + This behaves like :n:`tryif @expr then fail 0 tac "succeeds" else idtac`. + +Checking the success +~~~~~~~~~~~~~~~~~~~~ + +Coq provides a derived tactic to check that a tactic has *at least one* +success: + +.. tacn:: assert_succeeds @expr + + This behaves like + :n:`tryif (assert_fails tac) then fail 0 tac "fails" else idtac`. + +Solving +~~~~~~~ + +We may consider the first to solve (i.e. which generates no subgoal) +among a panel of tactics: + +.. tacn:: solve [{*| @expr}] + + The :n:`@expr__i` are evaluated to :n:`v__i` and :n:`v__i` must be + tactic values, for i=1,...,n. Supposing n>1, it applies :n:`v__1` to + each goal independently, if it doesn’t solve the goal then it tries to + apply :n:`v__2` and so on. It fails if there is no solving tactic. + + .. exn:: Cannot solve the goal + + .. tacv:: solve @expr + + This is an |Ltac| alias that gives a primitive access to the :n:`solve:` + tactical. See the :n:`first` tactical for more information. + +Identity +~~~~~~~~ + +The constant :n:`idtac` is the identity tactic: it leaves any goal unchanged but +it appears in the proof script. + +.. tacn:: idtac {* message_token} + + This prints the given tokens. Strings and integers are printed + literally. If a (term) variable is given, its contents are printed. + +Failing +~~~~~~~ + +.. tacn:: fail + + This is the always-failing tactic: it does not solve any + goal. It is useful for defining other tacticals since it can be caught by + :tacn:`try`, :tacn:`repeat`, :tacn:`match goal`, or the branching tacticals. The + :tacn:`fail` tactic will, however, succeed if all the goals have already been + solved. + + .. tacv:: fail @natural + + The number is the failure level. If no level is specified, it defaults to 0. + The level is used by :tacn:`try`, :tacn:`repeat`, :tacn:`match goal` and the branching + tacticals. If 0, it makes :tacn:`match goal` considering the next clause + (backtracking). If non zero, the current :tacn:`match goal` block, :tacn:`try`, + :tacn:`repeat`, or branching command is aborted and the level is decremented. In + the case of :n:`+`, a non-zero level skips the first backtrack point, even if + the call to :n:`fail @natural` is not enclosed in a :n:`+` command, + respecting the algebraic identity. + + .. tacv:: fail {* message_token} + + The given tokens are used for printing the failure message. + + .. tacv:: fail @natural {* message_token} + + This is a combination of the previous variants. + + .. tacv:: gfail + + This variant fails even if there are no goals left. + + .. tacv:: gfail {* message_token} + + .. tacv:: gfail @natural {* message_token} + + These variants fail with an error message or an error level even if + there are no goals left. Be careful however if Coq terms have to be + printed as part of the failure: term construction always forces the + tactic into the goals, meaning that if there are no goals when it is + evaluated, a tactic call like :n:`let x:=H in fail 0 x` will succeed. + + .. exn:: Tactic Failure message (level @natural). + +Timeout +~~~~~~~ + +We can force a tactic to stop if it has not finished after a certain +amount of time: + +.. tacn:: timeout @num @expr + + :n:`@expr` is evaluated to ``v`` which must be a tactic value. The tactic value + ``v`` is applied normally, except that it is interrupted after :n:`@num` seconds + if it is still running. In this case the outcome is a failure. + + .. warning:: + + For the moment, timeout is based on elapsed time in seconds, + which is very machine-dependent: a script that works on a quick machine + may fail on a slow one. The converse is even possible if you combine a + timeout with some other tacticals. This tactical is hence proposed only + for convenience during debug or other development phases, we strongly + advise you to not leave any timeout in final scripts. Note also that + this tactical isn’t available on the native Windows port of Coq. + +Timing a tactic +~~~~~~~~~~~~~~~ + +A tactic execution can be timed: + +.. tacn:: time @string @expr + + evaluates :n:`@expr` and displays the time the tactic expression ran, whether it + fails or successes. In case of several successes, the time for each successive + runs is displayed. Time is in seconds and is machine-dependent. The :n:`@string` + argument is optional. When provided, it is used to identify this particular + occurrence of time. + +Timing a tactic that evaluates to a term +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Tactic expressions that produce terms can be timed with the experimental +tactic + +.. tacn:: time_constr expr + + which evaluates :n:`@expr ()` and displays the time the tactic expression + evaluated, assuming successful evaluation. Time is in seconds and is + machine-dependent. + + This tactic currently does not support nesting, and will report times + based on the innermost execution. This is due to the fact that it is + implemented using the tactics + + .. tacn:: restart_timer @string + + and + + .. tacn:: finish_timing {? @string} @string + + which (re)set and display an optionally named timer, respectively. The + parenthesized string argument to :n:`finish_timing` is also optional, and + determines the label associated with the timer for printing. + + By copying the definition of :n:`time_constr` from the standard library, + users can achive support for a fixed pattern of nesting by passing + different :n:`@string` parameters to :n:`restart_timer` and :n:`finish_timing` + at each level of nesting. + + .. example:: + + .. coqtop:: all + + Ltac time_constr1 tac := + let eval_early := match goal with _ => restart_timer "(depth 1)" end in + let ret := tac () in + let eval_early := match goal with _ => finish_timing ( "Tactic evaluation" ) "(depth 1)" end in + ret. + + Goal True. + let v := time_constr + ltac:(fun _ => + let x := time_constr1 ltac:(fun _ => constr:(10 * 10)) in + let y := time_constr1 ltac:(fun _ => eval compute in x) in + y) in + pose v. + Abort. + +Local definitions +~~~~~~~~~~~~~~~~~ + +Local definitions can be done as follows: + +.. tacn:: let @ident__1 := @expr__1 {* with @ident__i := @expr__i} in @expr + + each :n:`@expr__i` is evaluated to :n:`v__i`, then, :n:`@expr` is evaluated + by substituting :n:`v__i` to each occurrence of :n:`@ident__i`, for + i=1,...,n. There is no dependencies between the :n:`@expr__i` and the + :n:`@ident__i`. + + Local definitions can be recursive by using :n:`let rec` instead of :n:`let`. + In this latter case, the definitions are evaluated lazily so that the rec + keyword can be used also in non recursive cases so as to avoid the eager + evaluation of local definitions. + + .. but rec changes the binding!! + +Application +~~~~~~~~~~~ + +An application is an expression of the following form: + +.. tacn:: @qualid {+ @tacarg} + + The reference :n:`@qualid` must be bound to some defined tactic definition + expecting at least as many arguments as the provided :n:`tacarg`. The + expressions :n:`@expr__i` are evaluated to :n:`v__i`, for i=1,...,n. + + .. what expressions ?? + +Function construction +~~~~~~~~~~~~~~~~~~~~~ + +A parameterized tactic can be built anonymously (without resorting to +local definitions) with: + +.. tacn:: fun {+ @ident} => @expr + + Indeed, local definitions of functions are a syntactic sugar for binding + a :n:`fun` tactic to an identifier. + +Pattern matching on terms +~~~~~~~~~~~~~~~~~~~~~~~~~ + +We can carry out pattern matching on terms with: + +.. tacn:: match @expr with {+| @cpattern__i => @expr__i} end + + The expression :n:`@expr` is evaluated and should yield a term which is + matched against :n:`cpattern__1`. The matching is non-linear: if a + metavariable occurs more than once, it should match the same expression + every time. It is first-order except on the variables of the form :n:`@?id` + that occur in head position of an application. For these variables, the + matching is second-order and returns a functional term. + + Alternatively, when a metavariable of the form :n:`?id` occurs under binders, + say :n:`x__1, …, x__n` and the expression matches, the + metavariable is instantiated by a term which can then be used in any + context which also binds the variables :n:`x__1, …, x__n` with + same types. This provides with a primitive form of matching under + context which does not require manipulating a functional term. + + If the matching with :n:`@cpattern__1` succeeds, then :n:`@expr__1` is + evaluated into some value by substituting the pattern matching + instantiations to the metavariables. If :n:`@expr__1` evaluates to a + tactic and the match expression is in position to be applied to a goal + (e.g. it is not bound to a variable by a :n:`let in`), then this tactic is + applied. If the tactic succeeds, the list of resulting subgoals is the + result of the match expression. If :n:`@expr__1` does not evaluate to a + tactic or if the match expression is not in position to be applied to a + goal, then the result of the evaluation of :n:`@expr__1` is the result + of the match expression. + + If the matching with :n:`@cpattern__1` fails, or if it succeeds but the + evaluation of :n:`@expr__1` fails, or if the evaluation of + :n:`@expr__1` succeeds but returns a tactic in execution position whose + execution fails, then :n:`cpattern__2` is used and so on. The pattern + :n:`_` matches any term and shunts all remaining patterns if any. If all + clauses fail (in particular, there is no pattern :n:`_`) then a + no-matching-clause error is raised. + + Failures in subsequent tactics do not cause backtracking to select new + branches or inside the right-hand side of the selected branch even if it + has backtracking points. + + .. exn:: No matching clauses for match + + No pattern can be used and, in particular, there is no :n:`_` pattern. + + .. exn:: Argument of match does not evaluate to a term + + This happens when :n:`@expr` does not denote a term. + + .. tacv:: multimatch @expr with {+| @cpattern__i => @expr__i} end + + Using multimatch instead of match will allow subsequent tactics to + backtrack into a right-hand side tactic which has backtracking points + left and trigger the selection of a new matching branch when all the + backtracking points of the right-hand side have been consumed. + + The syntax :n:`match …` is, in fact, a shorthand for :n:`once multimatch …`. + + .. tacv:: lazymatch @expr with {+| @cpattern__i => @expr__i} end + + Using lazymatch instead of match will perform the same pattern + matching procedure but will commit to the first matching branch + rather than trying a new matching if the right-hand side fails. If + the right-hand side of the selected branch is a tactic with + backtracking points, then subsequent failures cause this tactic to + backtrack. + + .. tacv:: context @ident [@cpattern] + + This special form of patterns matches any term with a subterm matching + cpattern. If there is a match, the optional :n:`@ident` is assigned the "matched + context", i.e. the initial term where the matched subterm is replaced by a + hole. The example below will show how to use such term contexts. + + If the evaluation of the right-hand-side of a valid match fails, the next + matching subterm is tried. If no further subterm matches, the next clause + is tried. Matching subterms are considered top-bottom and from left to + right (with respect to the raw printing obtained by setting option + :opt:`Printing All`). + + .. example:: + + .. coqtop:: all + + Ltac f x := + match x with + context f [S ?X] => + idtac X; (* To display the evaluation order *) + assert (p := eq_refl 1 : X=1); (* To filter the case X=1 *) + let x:= context f[O] in assert (x=O) (* To observe the context *) + end. + Goal True. + f (3+4). + +.. _ltac-match-goal: + +Pattern matching on goals +~~~~~~~~~~~~~~~~~~~~~~~~~ + +We can make pattern matching on goals using the following expression: + +.. we should provide the full grammar here + +.. tacn:: match goal with {+| {+ hyp} |- @cpattern => @expr } | _ => @expr end + + If each hypothesis pattern :n:`hyp`\ :sub:`1,i`, with i=1,...,m\ :sub:`1` is + matched (non-linear first-order unification) by an hypothesis of the + goal and if :n:`cpattern_1` is matched by the conclusion of the goal, + then :n:`@expr__1` is evaluated to :n:`v__1` by substituting the + pattern matching to the metavariables and the real hypothesis names + bound to the possible hypothesis names occurring in the hypothesis + patterns. If :n:`v__1` is a tactic value, then it is applied to the + goal. If this application fails, then another combination of hypotheses + is tried with the same proof context pattern. If there is no other + combination of hypotheses then the second proof context pattern is tried + and so on. If the next to last proof context pattern fails then + the last :n:`@expr` is evaluated to :n:`v` and :n:`v` is + applied. Note also that matching against subterms (using the :n:`context + @ident [ @cpattern ]`) is available and is also subject to yielding several + matchings. + + Failures in subsequent tactics do not cause backtracking to select new + branches or combinations of hypotheses, or inside the right-hand side of + the selected branch even if it has backtracking points. + + .. exn:: No matching clauses for match goal + + No clause succeeds, i.e. all matching patterns, if any, fail at the + application of the right-hand-side. + + .. note:: + + It is important to know that each hypothesis of the goal can be matched + by at most one hypothesis pattern. The order of matching is the + following: hypothesis patterns are examined from the right to the left + (i.e. hyp\ :sub:`i,m`\ :sub:`i`` before hyp\ :sub:`i,1`). For each + hypothesis pattern, the goal hypothesis are matched in order (fresher + hypothesis first), but it possible to reverse this order (older first) + with the :n:`match reverse goal with` variant. + + .. tacv:: multimatch goal with {+| {+ hyp} |- @cpattern => @expr } | _ => @expr end + + Using :n:`multimatch` instead of :n:`match` will allow subsequent tactics + to backtrack into a right-hand side tactic which has backtracking points + left and trigger the selection of a new matching branch or combination of + hypotheses when all the backtracking points of the right-hand side have + been consumed. + + The syntax :n:`match [reverse] goal …` is, in fact, a shorthand for + :n:`once multimatch [reverse] goal …`. + + .. tacv:: lazymatch goal with {+| {+ hyp} |- @cpattern => @expr } | _ => @expr end + + Using lazymatch instead of match will perform the same pattern matching + procedure but will commit to the first matching branch with the first + matching combination of hypotheses rather than trying a new matching if + the right-hand side fails. If the right-hand side of the selected branch + is a tactic with backtracking points, then subsequent failures cause + this tactic to backtrack. + +Filling a term context +~~~~~~~~~~~~~~~~~~~~~~ + +The following expression is not a tactic in the sense that it does not +produce subgoals but generates a term to be used in tactic expressions: + +.. tacn:: context @ident [@expr] + + :n:`@ident` must denote a context variable bound by a context pattern of a + match expression. This expression evaluates replaces the hole of the + value of :n:`@ident` by the value of :n:`@expr`. + + .. exn:: not a context variable + +Generating fresh hypothesis names +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Tactics sometimes have to generate new names for hypothesis. Letting the +system decide a name with the intro tactic is not so good since it is +very awkward to retrieve the name the system gave. The following +expression returns an identifier: + +.. tacn:: fresh {* component} + + It evaluates to an identifier unbound in the goal. This fresh identifier + is obtained by concatenating the value of the :n:`@component`s (each of them + is, either a :n:`@qualid` which has to refer to a (unqualified) name, or + directly a name denoted by a :n:`@string`). + + .. I don't understand this component thing. Couldn't we give the grammar? + + If the resulting name is already used, it is padded with a number so that it + becomes fresh. If no component is given, the name is a fresh derivative of + the name ``H``. + +Computing in a constr +~~~~~~~~~~~~~~~~~~~~~ + +Evaluation of a term can be performed with: + +.. tacn:: eval @redexpr in @term + + where :n:`@redexpr` is a reduction tactic among :tacn:`red`, :tacn:`hnf`, + :tacn:`compute`, :tacn:`simpl`, :tacn:`cbv`, :tacn:`lazy`, :tacn:`unfold`, + :tacn:`fold`, :tacn:`pattern`. + +Recovering the type of a term +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following returns the type of term: + +.. tacn:: type of @term + +Manipulating untyped terms +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. tacn:: uconstr : @term + + The terms built in |Ltac| are well-typed by default. It may not be + appropriate for building large terms using a recursive |Ltac| function: the + term has to be entirely type checked at each step, resulting in potentially + very slow behavior. It is possible to build untyped terms using |Ltac| with + the :n:`uconstr : @term` syntax. + +.. tacn:: type_term @term + + An untyped term, in |Ltac|, can contain references to hypotheses or to + |Ltac| variables containing typed or untyped terms. An untyped term can be + type-checked using the function type_term whose argument is parsed as an + untyped term and returns a well-typed term which can be used in tactics. + +Untyped terms built using :n:`uconstr :` can also be used as arguments to the +:tacn:`refine` tactic. In that case the untyped term is type +checked against the conclusion of the goal, and the holes which are not solved +by the typing procedure are turned into new subgoals. + +Counting the goals +~~~~~~~~~~~~~~~~~~ + +.. tacn:: numgoals + + The number of goals under focus can be recovered using the :n:`numgoals` + function. Combined with the guard command below, it can be used to + branch over the number of goals produced by previous tactics. + + .. example:: + + .. coqtop:: in + + Ltac pr_numgoals := let n := numgoals in idtac "There are" n "goals". + + Goal True /\ True /\ True. + split;[|split]. + + .. coqtop:: all + + all:pr_numgoals. + +Testing boolean expressions +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. tacn:: guard @test + + The :tacn:`guard` tactic tests a boolean expression, and fails if the expression + evaluates to false. If the expression evaluates to true, it succeeds + without affecting the proof. + + The accepted tests are simple integer comparisons. + + .. example:: + + .. coqtop:: in + + Goal True /\ True /\ True. + split;[|split]. + + .. coqtop:: all + + all:let n:= numgoals in guard n<4. + Fail all:let n:= numgoals in guard n=2. + + .. exn:: Condition not satisfied + +Proving a subgoal as a separate lemma +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. tacn:: abstract @expr + + From the outside, :n:`abstract @expr` is the same as :n:`solve @expr`. + Internally it saves an auxiliary lemma called ``ident_subproofn`` where + ``ident`` is the name of the current goal and ``n`` is chosen so that this is + a fresh name. Such an auxiliary lemma is inlined in the final proof term. + + This tactical is useful with tactics such as :tacn:`omega` or + :tacn:`discriminate` that generate huge proof terms. With that tool the user + can avoid the explosion at time of the Save command without having to cut + manually the proof in smaller lemmas. + + It may be useful to generate lemmas minimal w.r.t. the assumptions they + depend on. This can be obtained thanks to the option below. + + .. tacv:: abstract @expr using @ident + + Give explicitly the name of the auxiliary lemma. + + .. warning:: + + Use this feature at your own risk; explicitly named and reused subterms + don’t play well with asynchronous proofs. + + .. tacv:: transparent_abstract @expr + + Save the subproof in a transparent lemma rather than an opaque one. + + .. warning:: + + Use this feature at your own risk; building computationally relevant + terms with tactics is fragile. + + .. tacv:: transparent_abstract @expr using @ident + + Give explicitly the name of the auxiliary transparent lemma. + + .. warning:: + + Use this feature at your own risk; building computationally relevant terms + with tactics is fragile, and explicitly named and reused subterms + don’t play well with asynchronous proofs. + + .. exn:: Proof is not complete + :name: Proof is not complete (abstract) + +Tactic toplevel definitions +--------------------------- + +Defining |Ltac| functions +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Basically, |Ltac| toplevel definitions are made as follows: + +.. cmd:: Ltac @ident {* @ident} := @expr + + This defines a new |Ltac| function that can be used in any tactic + script or new |Ltac| toplevel definition. + + .. note:: + + The preceding definition can equivalently be written: + + :n:`Ltac @ident := fun {+ @ident} => @expr` + + Recursive and mutual recursive function definitions are also possible + with the syntax: + + .. cmdv:: Ltac @ident {* @ident} {* with @ident {* @ident}} := @expr + + It is also possible to *redefine* an existing user-defined tactic using the syntax: + + .. cmdv:: Ltac @qualid {* @ident} ::= @expr + + A previous definition of qualid must exist in the environment. The new + definition will always be used instead of the old one and it goes across + module boundaries. + + If preceded by the keyword Local the tactic definition will not be + exported outside the current module. + +Printing |Ltac| tactics +~~~~~~~~~~~~~~~~~~~~~~~ + +.. cmd:: Print Ltac @qualid. + + Defined |Ltac| functions can be displayed using this command. + +.. cmd:: Print Ltac Signatures + + This command displays a list of all user-defined tactics, with their arguments. + +Debugging |Ltac| tactics +------------------------ + +Info trace +~~~~~~~~~~ + +.. cmd:: Info @num @expr + + This command can be used to print the trace of the path eventually taken by an + |Ltac| script. That is, the list of executed tactics, discarding + all the branches which have failed. To that end the Info command can be + used with the following syntax. + + + The number :n:`@num` is the unfolding level of tactics in the trace. At level + 0, the trace contains a sequence of tactics in the actual script, at level 1, + the trace will be the concatenation of the traces of these tactics, etc… + + .. example:: + + .. coqtop:: in reset + + Ltac t x := exists x; reflexivity. + Goal exists n, n=0. + + .. coqtop:: all + + Info 0 t 1||t 0. + + .. coqtop:: in + + Undo. + + .. coqtop:: all + + Info 1 t 1||t 0. + + The trace produced by ``Info`` tries its best to be a reparsable + |Ltac| script, but this goal is not achievable in all generality. + So some of the output traces will contain oddities. + + As an additional help for debugging, the trace produced by ``Info`` contains + (in comments) the messages produced by the idtac + tacticals \ `4.2 <#ltac%3Aidtac>`__ at the right possition in the + script. In particular, the calls to idtac in branches which failed are + not printed. + + .. opt:: Info Level @num. + + This option is an alternative to the ``Info`` command. + + This will automatically print the same trace as :n:`Info @num` at each + tactic call. The unfolding level can be overridden by a call to the + ``Info`` command. + +Interactive debugger +~~~~~~~~~~~~~~~~~~~~ + +.. opt:: Ltac Debug + + This option governs the step-by-step debugger that comes with the |Ltac| interpreter + +When the debugger is activated, it stops at every step of the evaluation of +the current |Ltac| expression and it prints information on what it is doing. +The debugger stops, prompting for a command which can be one of the +following: + ++-----------------+-----------------------------------------------+ +| simple newline: | go to the next step | ++-----------------+-----------------------------------------------+ +| h: | get help | ++-----------------+-----------------------------------------------+ +| x: | exit current evaluation | ++-----------------+-----------------------------------------------+ +| s: | continue current evaluation without stopping | ++-----------------+-----------------------------------------------+ +| r n: | advance n steps further | ++-----------------+-----------------------------------------------+ +| r string: | advance up to the next call to “idtac string” | ++-----------------+-----------------------------------------------+ + +A non-interactive mode for the debugger is available via the option: + +.. opt:: Ltac Batch Debug + + This option has the effect of presenting a newline at every prompt, when + the debugger is on. The debug log thus created, which does not require + user input to generate when this option is set, can then be run through + external tools such as diff. + +Profiling |Ltac| tactics +~~~~~~~~~~~~~~~~~~~~~~~~ + +It is possible to measure the time spent in invocations of primitive +tactics as well as tactics defined in |Ltac| and their inner +invocations. The primary use is the development of complex tactics, +which can sometimes be so slow as to impede interactive usage. The +reasons for the performence degradation can be intricate, like a slowly +performing |Ltac| match or a sub-tactic whose performance only +degrades in certain situations. The profiler generates a call tree and +indicates the time spent in a tactic depending its calling context. Thus +it allows to locate the part of a tactic definition that contains the +performance bug. + +.. opt:: Ltac Profiling + + This option enables and disables the profiler. + +.. cmd:: Show Ltac Profile + + Prints the profile + + .. cmdv:: Show Ltac Profile @string + + Prints a profile for all tactics that start with :n:`@string`. Append a period + (.) to the string if you only want exactly that name. + +.. cmd:: Reset Ltac Profile + + Resets the profile, that is, deletes all accumulated information. + + .. warning:: + + Backtracking across a Reset Ltac Profile will not restore the information. + +.. coqtop:: reset in + + Require Import Coq.omega.Omega. + + Ltac mytauto := tauto. + Ltac tac := intros; repeat split; omega || mytauto. + + Notation max x y := (x + (y - x)) (only parsing). + + Goal forall x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z, + max x (max y z) = max (max x y) z /\ max x (max y z) = max (max x y) z + /\ (A /\ B /\ C /\ D /\ E /\ F /\ G /\ H /\ I /\ J /\ K /\ L /\ M /\ N /\ O /\ P /\ Q /\ R /\ S /\ T /\ U /\ V /\ W /\ X /\ Y /\ Z + -> Z /\ Y /\ X /\ W /\ V /\ U /\ T /\ S /\ R /\ Q /\ P /\ O /\ N /\ M /\ L /\ K /\ J /\ I /\ H /\ G /\ F /\ E /\ D /\ C /\ B /\ A). + Proof. + +.. coqtop:: all + + Set Ltac Profiling. + tac. + Show Ltac Profile. + Show Ltac Profile "omega". + +.. coqtop:: in + + Abort. + Unset Ltac Profiling. + +.. tacn:: start ltac profiling + + This tactic behaves like :tacn:`idtac` but enables the profiler. + +.. tacn:: stop ltac profiling + + Similarly to :tacn:`start ltac profiling`, this tactic behaves like + :tacn:`idtac`. Together, they allow you to exclude parts of a proof script + from profiling. + +.. tacn:: reset ltac profile + + This tactic behaves like the corresponding vernacular command + and allow displaying and resetting the profile from tactic scripts for + benchmarking purposes. + +.. tacn:: show ltac profile + + This tactic behaves like the corresponding vernacular command + and allow displaying and resetting the profile from tactic scripts for + benchmarking purposes. + +.. tacn:: show ltac profile @string + + This tactic behaves like the corresponding vernacular command + and allow displaying and resetting the profile from tactic scripts for + benchmarking purposes. + +You can also pass the ``-profile-ltac`` command line option to ``coqc``, which +performs a ``Set Ltac Profiling`` at the beginning of each document, and a +``Show Ltac Profile`` at the end. + +.. warning:: + + Note that the profiler currently does not handle backtracking into + multi-success tactics, and issues a warning to this effect in many cases + when such backtracking occurs. + +Run-time optimization tactic +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. tacn:: optimize_heap + +This tactic behaves like :n:`idtac`, except that running it compacts the +heap in the OCaml run-time system. It is analogous to the Vernacular +command :cmd:`Optimize Heap`. diff --git a/doc/sphinx/proof-engine/proof-handling.rst b/doc/sphinx/proof-engine/proof-handling.rst index adf3da3eb..a77b127eb 100644 --- a/doc/sphinx/proof-engine/proof-handling.rst +++ b/doc/sphinx/proof-engine/proof-handling.rst @@ -20,20 +20,18 @@ prove. Initially, the list consists only in the theorem itself. After having applied some tactics, the list of goals contains the subgoals generated by the tactics. -To each subgoal is associated a number of hypotheses called the *local -context* of the goal. Initially, the local context contains the local -variables and hypotheses of the current section (see Section :ref:`TODO_gallina_assumptions`) -and the local variables and hypotheses of the theorem statement. It is -enriched by the use of certain tactics (see e.g. ``intro`` in Section -:ref:`managingthelocalcontext`). +To each subgoal is associated a number of hypotheses called the *local context* +of the goal. Initially, the local context contains the local variables and +hypotheses of the current section (see Section :ref:`gallina-assumptions`) and +the local variables and hypotheses of the theorem statement. It is enriched by +the use of certain tactics (see e.g. :tacn:`intro`). When a proof is completed, the message ``Proof completed`` is displayed. One can then register this proof as a defined constant in the environment. Because there exists a correspondence between proofs and -terms of λ-calculus, known as the *Curry-Howard isomorphism* [[How80]_, -[Bar81]_, [Gir89]_, [Hue88]_ ], |Coq| -stores proofs as terms of |Cic|. Those terms -are called *proof terms*. +terms of λ-calculus, known as the *Curry-Howard isomorphism* +:cite:`How80,Bar81,Gir89,Hue88`, |Coq| stores proofs as terms of |Cic|. Those +terms are called *proof terms*. .. exn:: No focused proof @@ -41,16 +39,15 @@ are called *proof terms*. Coq raises this error message when one attempts to use a proof editing command out of the proof editing mode. +.. _proof-editing-mode: + Switching on/off the proof editing mode ------------------------------------------- -The proof editing mode is entered by asserting a statement, which -typically is the assertion of a theorem: - -.. cmd:: Theorem @ident [@binders] : @form. - -The list of assertion commands is given in Section :ref:TODO-assertions_and_proof`. The -command ``Goal`` can also be used. +The proof editing mode is entered by asserting a statement, which typically is +the assertion of a theorem using an assertion command like :cmd:`Theorem`. The +list of assertion commands is given in Section :ref:`Assertions`. The command +:cmd:`Goal` can also be used. .. cmd:: Goal @form. @@ -93,14 +90,13 @@ Forces the name of the original goal to be :n:`@ident`. This command (and the following ones) can only be used if the original goal has been opened using the ``Goal`` command. - .. cmd:: Admitted. This command is available in interactive editing proof mode to give up the current proof and declare the initial goal as an axiom. - .. cmd:: Proof @term. + :name: Proof `term` This command applies in proof editing mode. It is equivalent to @@ -119,13 +115,13 @@ closing ``Qed``. See also: ``Proof with tactic.`` in Section -:ref:`setimpautotactics`. +:ref:`tactics-implicit-automation`. .. cmd:: Proof using @ident1 ... @identn. This command applies in proof editing mode. It declares the set of -section variables (see :ref:`TODO-gallina-assumptions`) used by the proof. At ``Qed`` time, the +section variables (see :ref:`gallina-assumptions`) used by the proof. At ``Qed`` time, the system will assert that the set of section variables actually used in the proof is a subset of the declared one. @@ -136,7 +132,7 @@ example if ``T`` is variable and a is a variable of type ``T``, the commands .. cmdv:: Proof using @ident1 ... @identn with @tactic. -in Section :ref:`setimpautotactics`. +in Section :ref:`tactics-implicit-automation`. .. cmdv:: Proof using All. @@ -262,11 +258,11 @@ Existentials`` (described in Section :ref:`requestinginformation`). This command is intended to be used to instantiate existential variables when the proof is completed but some uninstantiated existential variables remain. To instantiate existential variables -during proof edition, you should use the tactic instantiate. +during proof edition, you should use the tactic :tacn:`instantiate`. See also: ``instantiate (num:= term).`` in Section -:ref:`TODO-controllingtheproofflow`. +:ref:`controllingtheproofflow`. See also: ``Grab Existential Variables.`` below. @@ -327,6 +323,7 @@ last ``Focus`` command. Succeeds if the proof is fully unfocused, fails is there are some goals out of focus. +.. _curly-braces: .. cmd:: %{ %| %} @@ -351,12 +348,14 @@ Error messages: You are trying to use ``}`` but the current subproof has not been fully solved. .. exn:: No such goal + :name: No such goal (focusing) .. exn:: Brackets only support the single numbered goal selector - See also error messages about bullets below. +.. _bullets: + Bullets ``````` @@ -434,6 +433,7 @@ This makes bullets inactive. This makes bullets active (this is the default behavior). +.. _requestinginformation: Requesting information ---------------------- @@ -456,7 +456,7 @@ Displays only the :n:`@num`-th subgoal. Displays the named goal :n:`@ident`. This is useful in particular to display a shelved goal but only works if the corresponding existential variable has been named by the user -(see :ref:`exvariables`) as in the following example. +(see :ref:`existential-variables`) as in the following example. .. example:: @@ -536,7 +536,7 @@ debugging universe inconsistencies. .. cmd:: Guarded. -Some tactics (e.g. refine :ref:`applyingtheorems`) allow to build proofs using +Some tactics (e.g. :tacn:`refine` :ref:`applyingtheorems`) allow to build proofs using fixpoint or co-fixpoint constructions. Due to the incremental nature of interactive proof construction, the check of the termination (or guardedness) of the recursive calls in the fixpoint or cofixpoint @@ -591,4 +591,4 @@ the ongoing proof. This command forces the |OCaml| runtime to perform a heap compaction. This is in general an expensive operation. See: `OCaml Gc <http://caml.inria.fr/pub/docs/manual-ocaml/libref/Gc.html#VALcompact>`_ -There is also an analogous tactic ``optimize_heap`` (see~:ref:`tactic-optimizeheap`) +There is also an analogous tactic :tac:`optimize_heap`. diff --git a/doc/sphinx/proof-engine/ssreflect-proof-language.rst b/doc/sphinx/proof-engine/ssreflect-proof-language.rst index df5b36297..074c6f1e2 100644 --- a/doc/sphinx/proof-engine/ssreflect-proof-language.rst +++ b/doc/sphinx/proof-engine/ssreflect-proof-language.rst @@ -5185,6 +5185,7 @@ equivalences are indeed taken into account, otherwise only single |SSR| proposes an extension of the Search command. Its syntax is: .. cmd:: Search {? @pattern } {* {? - } %( @string %| @pattern %) {? % @ident} } {? in {+ {? - } @qualid } } + :name: Search (ssreflect) where :token:`qualid` is the name of an open module. This command returns the list of lemmas: diff --git a/doc/sphinx/proof-engine/tactics.rst b/doc/sphinx/proof-engine/tactics.rst index 2af73c28e..08aa7110d 100644 --- a/doc/sphinx/proof-engine/tactics.rst +++ b/doc/sphinx/proof-engine/tactics.rst @@ -24,7 +24,7 @@ Each (sub)goal is denoted with a number. The current goal is numbered 1. By default, a tactic is applied to the current goal, but one can address a particular goal in the list by writing n:tactic which means “apply tactic tactic to goal number n”. We can show the list of -subgoals by typing Show (see Section :ref:`TODO-7.3.1-Show`). +subgoals by typing Show (see Section :ref:`requestinginformation`). Since not every rule applies to a given statement, every tactic cannot be used to reduce any goal. In other words, before applying a tactic @@ -34,15 +34,16 @@ satisfied. If it is not the case, the tactic raises an error message. Tactics are built from atomic tactics and tactic expressions (which extends the folklore notion of tactical) to combine those atomic tactics. This chapter is devoted to atomic tactics. The tactic -language will be described in Chapter :ref:`TODO-9-Thetacticlanguage`. +language will be described in Chapter :ref:`ltac`. + +.. _invocation-of-tactics: Invocation of tactics ------------------------- A tactic is applied as an ordinary command. It may be preceded by a -goal selector (see Section :ref:`TODO-9.2-Semantics`). If no selector is -specified, the default selector (see Section -:ref:`TODO-8.1.1-Setdefaultgoalselector`) is used. +goal selector (see Section :ref:`ltac-semantics`). If no selector is +specified, the default selector is used. .. _tactic_invocation_grammar: @@ -94,7 +95,7 @@ bindings_list`` where ``bindings_list`` may be of two different forms: + A bindings list can also be a simple list of terms :n:`{* term}`. In that case the references to which these terms correspond are determined by the tactic. In case of ``induction``, ``destruct``, ``elim`` - and ``case`` (see :ref:`TODO-9-Thetacticlanguage`) the terms have to + and ``case`` (see :ref:`ltac`) the terms have to provide instances for all the dependent products in the type of term while in the case of ``apply``, or of ``constructor`` and its variants, only instances for the dependent products that are not bound in the conclusion of the type @@ -126,9 +127,9 @@ occurrences have to be selected in the hypotheses named :n:`@ident`. If no numbe are given for hypothesis :n:`@ident`, then all the occurrences of `term` in the hypothesis are selected. If numbers are given, they refer to occurrences of `term` when the term is printed using option ``Set Printing All`` (see -:ref:`TODO-2.9-Printingconstructionsinfull`), counting from left to right. In +:ref:`printing_constructions_full`), counting from left to right. In particular, occurrences of `term` in implicit arguments (see -:ref:`TODO-2.7-Implicitarguments`) or coercions (see :ref:`TODO-2.8-Coercions`) +:ref:`ImplicitArguments`) or coercions (see :ref:`Coercions`) are counted. If a minus sign is given between at and the list of occurrences, it @@ -154,10 +155,11 @@ Here are some tactics that understand occurrences clauses: ``set``, ``remember`` , ``induction``, ``destruct``. -See also: :ref:`TODO-8.3.7-Managingthelocalcontext`, -:ref:`TODO-8.5.2-Caseanalysisandinduction`, -:ref:`TODO-2.9-Printingconstructionsinfull`. +See also: :ref:`Managingthelocalcontext`, +:ref:`caseanalysisandinduction`, +:ref:`printing_constructions_full`. +.. _applyingtheorems: Applying theorems --------------------- @@ -168,7 +170,7 @@ Applying theorems This tactic applies to any goal. It gives directly the exact proof term of the goal. Let ``T`` be our goal, let ``p`` be a term of type ``U`` then ``exact p`` succeeds iff ``T`` and ``U`` are convertible (see -:ref:`TODO-4.3-Conversionrules`). +:ref:`Conversion-rules`). .. exn:: Not an exact proof. @@ -277,7 +279,7 @@ gets the form :g:`(fun x => Q) u`:sub:`1` :g:`...` :g:`u`:sub:`n`. The apply tactic failed to match the conclusion of term and the current goal. You can help the apply tactic by transforming your goal with the -:ref:`change <change_term>` or :tacn:`pattern` tactics. +:tacn:`change` or :tacn:`pattern` tactics. .. exn:: Unable to find an instance for the variables {+ @ident}. @@ -285,7 +287,7 @@ This occurs when some instantiations of the premises of term are not deducible from the unification. This is the case, for instance, when you want to apply a transitivity property. In this case, you have to use one of the variants below: -.. cmd:: apply @term with {+ @term} +.. tacv:: apply @term with {+ @term} Provides apply with explicit instantiations for all dependent premises of the type of term that do not occur in the conclusion and consequently cannot be @@ -314,7 +316,7 @@ generated by ``apply term``:sub:`i` , starting from the application of The tactic ``eapply`` behaves like ``apply`` but it does not fail when no instantiations are deducible for some variables in the premises. Rather, it turns these variables into existential variables which are variables still to -instantiate (see :ref:`TODO-2.11-ExistentialVariables`). The instantiation is +instantiate (see :ref:`Existential-Variables`). The instantiation is intended to be found later in the proof. .. tacv:: simple apply @term. @@ -598,7 +600,7 @@ Managing the local context This tactic applies to a goal that is either a product or starts with a let binder. If the goal is a product, the tactic implements the "Lam" rule given in -:ref:`TODO-4.2-Typing-rules` [1]_. If the goal starts with a let binder, then the +:ref:`Typing-rules` [1]_. If the goal starts with a let binder, then the tactic implements a mix of the "Let" and "Conv". If the current goal is a dependent product :math:`\forall` :g:`x:T, U` (resp @@ -632,14 +634,14 @@ be applied or the goal is not head-reducible. .. note:: If a name used by intro hides the base name of a global constant then the latter can still be referred to by a qualified name - (see :ref:`TODO-2.6.2-Qualified-names`). + (see :ref:`Qualified-names`). .. tacv:: intros {+ @ident}. This is equivalent to the composed tactic :n:`intro @ident; ... ; intro @ident`. More generally, the ``intros`` tactic takes a pattern as argument in order to introduce names for components of an inductive definition or to clear introduced hypotheses. This is - explained in :ref:`TODO-8.3.2`. + explained in :ref:`Managingthelocalcontext`. .. tacv:: intros until @ident @@ -1067,7 +1069,7 @@ The name of the hypothesis in the proof-term, however, is left unchanged. This decomposes record types (inductive types with one constructor, like "and" and "exists" and those defined with the Record macro, see - :ref:`TODO-2.1`). + :ref:`record-types`). .. _controllingtheproofflow: @@ -1089,7 +1091,7 @@ Controlling the proof flow .. tacv:: assert form - This behaves as :n:`assert (@ident : form ) but :n:`@ident` is generated by + This behaves as :n:`assert (@ident : form)` but :n:`@ident` is generated by Coq. .. tacv:: assert form by tactic @@ -1098,6 +1100,7 @@ Controlling the proof flow generated by assert. .. exn:: Proof is not complete + :name: Proof is not complete (assert) .. tacv:: assert form as intro_pattern @@ -1177,7 +1180,7 @@ Controlling the proof flow .. tacv:: cut form This tactic applies to any goal. It implements the non-dependent case of - the “App” rule given in :ref:`TODO-4.2`. (This is Modus Ponens inference + the “App” rule given in :ref:`typing-rules`. (This is Modus Ponens inference rule.) :n:`cut U` transforms the current goal :g:`T` into the two following subgoals: :g:`U -> T` and :g:`U`. The subgoal :g:`U -> T` comes first in the list of remaining subgoal to prove. @@ -1268,7 +1271,7 @@ name of the variable (here :g:`n`) is chosen based on :g:`T`. :n:`refine @term` (preferred alternative). .. note:: To be able to refer to an existential variable by name, the user - must have given the name explicitly (see :ref:`TODO-2.11`). + must have given the name explicitly (see :ref:`Existential-Variables`). .. note:: When you are referring to hypotheses which you did not name explicitly, be aware that Coq may make a different decision on how to @@ -1353,11 +1356,13 @@ goals cannot be closed with :g:`Qed` but only with :g:`Admitted`. then required to prove that False is indeed provable in the current context. This tactic is a macro for :n:`elimtype False`. +.. _CaseAnalysisAndInduction: + Case analysis and induction ------------------------------- The tactics presented in this section implement induction or case -analysis on inductive or co-inductive objects (see :ref:`TODO-4.5`). +analysis on inductive or co-inductive objects (see :ref:`inductive-definitions`). .. tacn:: destruct @term :name: destruct @@ -1746,7 +1751,7 @@ analysis on inductive or co-inductive objects (see :ref:`TODO-4.5`). results equivalent to ``inversion`` or ``dependent inversion`` if the hypothesis is dependent. -See also :ref:`TODO-10.1-dependentinduction` for a larger example of ``dependent induction`` +See also the larger example of :tacn:`dependent induction` and an explanation of the underlying technique. .. tacn:: function induction (@qualid {+ @term}) @@ -1754,8 +1759,8 @@ and an explanation of the underlying technique. The tactic functional induction performs case analysis and induction following the definition of a function. It makes use of a principle - generated by ``Function`` (see :ref:`TODO-2.3-Advancedrecursivefunctions`) or - ``Functional Scheme`` (see :ref:`TODO-13.2-Generationofinductionschemeswithfunctionalscheme`). + generated by ``Function`` (see :ref:`advanced-recursive-functions`) or + ``Functional Scheme`` (see :ref:`functional-scheme`). Note that this tactic is only available after a .. example:: @@ -1781,22 +1786,22 @@ and an explanation of the underlying technique. :n:`functional induction (f x1 x2 x3)` is actually a wrapper for :n:`induction x1, x2, x3, (f x1 x2 x3) using @qualid` followed by a cleaning phase, where :n:`@qualid` is the induction principle registered for :g:`f` - (by the ``Function`` (see :ref:`TODO-2.3-Advancedrecursivefunctions`) or - ``Functional Scheme`` (see :ref:`TODO-13.2-Generationofinductionschemeswithfunctionalscheme`) + (by the ``Function`` (see :ref:`advanced-recursive-functions`) or + ``Functional Scheme`` (see :ref:`functional-scheme`) command) corresponding to the sort of the goal. Therefore ``functional induction`` may fail if the induction scheme :n:`@qualid` is not - defined. See also :ref:`TODO-2.3-Advancedrecursivefunctions` for the function + defined. See also :ref:`advanced-recursive-functions` for the function terms accepted by ``Function``. .. note:: There is a difference between obtaining an induction scheme - for a function by using :g:`Function` (see :ref:`TODO-2.3-Advancedrecursivefunctions`) + for a function by using :g:`Function` (see :ref:`advanced-recursive-functions`) and by using :g:`Functional Scheme` after a normal definition using - :g:`Fixpoint` or :g:`Definition`. See :ref:`TODO-2.3-Advancedrecursivefunctions` + :g:`Fixpoint` or :g:`Definition`. See :ref:`advanced-recursive-functions` for details. -See also: :ref:`TODO-2.3-Advancedrecursivefunctions` - :ref:`TODO-13.2-Generationofinductionschemeswithfunctionalscheme` +See also: :ref:`advanced-recursive-functions` + :ref:`functional-scheme` :tacn:`inversion` .. exn:: Cannot find induction information on @qualid @@ -1902,7 +1907,7 @@ injected object has a dependent type :g:`P` with its two instances in different types :g:`(P t`:sub:`1` :g:`... t`:sub:`n` :g:`)` and :g:`(P u`:sub:`1` :g:`... u`:sub:`n` :sub:`)`. If :g:`t`:sub:`1` and :g:`u`:sub:`1` are the same and have for type an inductive type for which a decidable -equality has been declared using the command ``Scheme Equality`` (see :ref:`TODO-13.1-GenerationofinductionprincipleswithScheme`), +equality has been declared using the command ``Scheme Equality`` (see :ref:`proofschemes-induction-principles`), the use of a sigma type is avoided. .. note:: @@ -1984,7 +1989,7 @@ turned off by setting the option ``Set Keep Proof Equalities``. .. note:: As ``inversion`` proofs may be large in size, we recommend the user to stock the lemmas whenever the same instance needs to be - inverted several times. See :ref:`TODO-13.3-Generationofinversionprincipleswithderiveinversion`. + inverted several times. See :ref:`derive-inversion`. .. note:: Part of the behavior of the ``inversion`` tactic is to generate @@ -2300,7 +2305,7 @@ turned off by setting the option ``Set Keep Proof Equalities``. arguments are correct is done only at the time of registering the lemma in the environment. To know if the use of induction hypotheses is correct at some time of the interactive development of a proof, use - the command ``Guarded`` (see :ref:`TODO-7.3.2-Guarded`). + the command ``Guarded`` (see Section :ref:`requestinginformation`). .. tacv:: fix @ident @num with {+ (ident {+ @binder} [{struct @ident}] : @type)} @@ -2321,7 +2326,7 @@ turned off by setting the option ``Set Keep Proof Equalities``. done only at the time of registering the lemma in the environment. To know if the use of coinduction hypotheses is correct at some time of the interactive development of a proof, use the command ``Guarded`` - (see :ref:`TODO-7.3.2-Guarded`). + (see Section :ref:`requestinginformation`). .. tacv:: cofix @ident with {+ (@ident {+ @binder} : @type)} @@ -2335,7 +2340,7 @@ Rewriting expressions --------------------- These tactics use the equality :g:`eq:forall A:Type, A->A->Prop` defined in -file ``Logic.v`` (see :ref:`TODO-3.1.2-Logic`). The notation for :g:`eq T t u` is +file ``Logic.v`` (see :ref:`coq-library-logic`). The notation for :g:`eq T t u` is simply :g:`t=u` dropping the implicit type of :g:`t` and :g:`u`. .. tacn:: rewrite @term @@ -2546,7 +2551,7 @@ then replaces the goal by :n:`R @term @term` and adds a new goal stating Lemmas are added to the database using the command ``Declare Left Step @term.`` The tactic is especially useful for parametric setoids which are not accepted as regular setoids for :tacn:`rewrite` and :tacn:`setoid_replace` (see -:ref:`TODO-27-Generalizedrewriting`). +:ref:`Generalizedrewriting`). .. tacv:: stepl @term by tactic @@ -2564,7 +2569,7 @@ as regular setoids for :tacn:`rewrite` and :tacn:`setoid_replace` (see :name: change This tactic applies to any goal. It implements the rule ``Conv`` given in - :ref:`TODO-4.4-Subtypingrules`. :g:`change U` replaces the current goal `T` + :ref:`subtyping-rules`. :g:`change U` replaces the current goal `T` with `U` providing that `U` is well-formed and that `T` and `U` are convertible. @@ -2637,7 +2642,7 @@ the conversion in hypotheses :n:`{+ @ident}`. the normalization of the goal according to the specified flags. In correspondence with the kinds of reduction considered in Coq namely :math:`\beta` (reduction of functional application), :math:`\delta` - (unfolding of transparent constants, see :ref:`TODO-6.10.2-Transparent`), + (unfolding of transparent constants, see :ref:`vernac-controlling-the-reduction-strategies`), :math:`\iota` (reduction of pattern-matching over a constructed term, and unfolding of :g:`fix` and :g:`cofix` expressions) and :math:`\zeta` (contraction of local definitions), the @@ -2649,7 +2654,7 @@ the conversion in hypotheses :n:`{+ @ident}`. second case the constant to unfold to all but the ones explicitly mentioned. Notice that the ``delta`` flag does not apply to variables bound by a let-in construction inside the :n:`@term` itself (use here the ``zeta`` flag). In - any cases, opaque constants are not unfolded (see :ref:`TODO-6.10.1-Opaque`). + any cases, opaque constants are not unfolded (see :ref:`vernac-controlling-the-reduction-strategies`). Normalization according to the flags is done by first evaluating the head of the expression into a *weak-head* normal form, i.e. until the @@ -2768,7 +2773,7 @@ the conversion in hypotheses :n:`{+ @ident}`. :n:`hnf`. .. note:: - The :math:`\delta` rule only applies to transparent constants (see :ref:`TODO-6.10.1-Opaque` + The :math:`\delta` rule only applies to transparent constants (see :ref:`vernac-controlling-the-reduction-strategies` on transparency and opacity). .. tacn:: cbn @@ -2906,7 +2911,7 @@ the conversion in hypotheses :n:`{+ @ident}`. This tactic applies to any goal. The argument qualid must denote a defined transparent constant or local definition (see - :ref:`TODO-1.3.2-Definitions` and :ref:`TODO-6.10.2-Transparent`). The tactic + :ref:`gallina-definitions` and :ref:`vernac-controlling-the-reduction-strategies`). The tactic ``unfold`` applies the :math:`\delta` rule to each occurrence of the constant to which :n:`@qualid` refers in the current goal and then replaces it with its :math:`\beta`:math:`\iota`-normal form. @@ -2942,7 +2947,7 @@ the conversion in hypotheses :n:`{+ @ident}`. This is variant of :n:`unfold @string` where :n:`@string` gets its interpretation from the scope bound to the delimiting key :n:`key` - instead of its default interpretation (see :ref:`TODO-12.2.2-Localinterpretationrulesfornotations`). + instead of its default interpretation (see :ref:`Localinterpretationrulesfornotations`). .. tacv:: unfold {+, qualid_or_string at {+, @num}} This is the most general form, where :n:`qualid_or_string` is either a @@ -3389,7 +3394,7 @@ The ``hint_definition`` is one of the following expressions: + :n:`Cut @regexp` .. warning:: these hints currently only apply to typeclass - proof search and the ``typeclasses eauto`` tactic (:ref:`TODO-20.6.5-typeclasseseauto`). + proof search and the ``typeclasses eauto`` tactic (:ref:`typeclasses-eauto`). This command can be used to cut the proof-search tree according to a regular expression matching paths to be cut. The grammar for regular expressions is @@ -3521,7 +3526,7 @@ at every moment. (left to right). Notice that the rewriting bases are distinct from the ``auto`` hint bases and thatauto does not take them into account. - This command is synchronous with the section mechanism (see :ref:`TODO-2.4-Sectionmechanism`): + This command is synchronous with the section mechanism (see :ref:`section-mechanism`): when closing a section, all aliases created by ``Hint Rewrite`` in that section are lost. Conversely, when loading a module, all ``Hint Rewrite`` declarations at the global level of that module are loaded. @@ -3592,6 +3597,8 @@ non-imported hints. When set, it changes the behavior of an unloaded hint to a immediate fail tactic, allowing to emulate an import-scoped hint mechanism. +.. _tactics-implicit-automation: + Setting implicit automation tactics ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -3602,40 +3609,37 @@ Setting implicit automation tactics In this case the tactic command typed by the user is equivalent to ``tactic``:sub:`1` ``;tactic``. -See also: Proof. in :ref:`TODO-7.1.4-Proofterm`. - -**Variants:** + See also: ``Proof.`` in :ref:`proof-editing-mode`. -.. cmd:: Proof with tactic using {+ @ident} - Combines in a single line ``Proof with`` and ``Proof using``, see :ref:`TODO-7.1.5-Proofusing` + .. cmdv:: Proof with tactic using {+ @ident} -.. cmd:: Proof using {+ @ident} with tactic + Combines in a single line ``Proof with`` and ``Proof using``, see :ref:`proof-editing-mode` - Combines in a single line ``Proof with`` and ``Proof using``, see :ref:`TODO-7.1.5-Proofusing` + .. cmdv:: Proof using {+ @ident} with tactic -.. cmd:: Declare Implicit Tactic tactic + Combines in a single line ``Proof with`` and ``Proof using``, see :ref:`proof-editing-mode` - This command declares a tactic to be used to solve implicit arguments - that Coq does not know how to solve by unification. It is used every - time the term argument of a tactic has one of its holes not fully - resolved. + .. cmd:: Declare Implicit Tactic tactic -Here is an example: + This command declares a tactic to be used to solve implicit arguments + that Coq does not know how to solve by unification. It is used every + time the term argument of a tactic has one of its holes not fully + resolved. -.. example:: + .. example:: - .. coqtop:: all + .. coqtop:: all - Parameter quo : nat -> forall n:nat, n<>0 -> nat. - Notation "x // y" := (quo x y _) (at level 40). - Declare Implicit Tactic assumption. - Goal forall n m, m<>0 -> { q:nat & { r | q * m + r = n } }. - intros. - exists (n // m). + Parameter quo : nat -> forall n:nat, n<>0 -> nat. + Notation "x // y" := (quo x y _) (at level 40). + Declare Implicit Tactic assumption. + Goal forall n m, m<>0 -> { q:nat & { r | q * m + r = n } }. + intros. + exists (n // m). - The tactic ``exists (n // m)`` did not fail. The hole was solved - by ``assumption`` so that it behaved as ``exists (quo n m H)``. + The tactic ``exists (n // m)`` did not fail. The hole was solved + by ``assumption`` so that it behaved as ``exists (quo n m H)``. .. _decisionprocedures: @@ -3713,7 +3717,7 @@ and then uses :tacn:`auto` which completes the proof. Originally due to César Muñoz, these tactics (:tacn:`tauto` and :tacn:`intuition`) have been completely re-engineered by David Delahaye using -mainly the tactic language (see :ref:`TODO-9-thetacticlanguage`). The code is +mainly the tactic language (see :ref:`ltac`). The code is now much shorter and a significant increase in performance has been noticed. The general behavior with respect to dependent types, unfolding and introductions has slightly changed to get clearer semantics. This may lead to @@ -3878,7 +3882,7 @@ succeeds, and results in an error otherwise. .. tacv:: unify @term @term with @ident Unification takes the transparency information defined in the hint database - :n:`@ident` into account (see :ref:`the hints databases for auto and eauto <the-hints-databases-for-auto-and-eauto>`). + :n:`@ident` into account (see :ref:`the hints databases for auto and eauto <thehintsdatabasesforautoandeauto>`). .. tacn:: is_evar @term :name: is_evar @@ -4044,7 +4048,7 @@ Inversion :tacn:`functional inversion` is a tactic that performs inversion on hypothesis :n:`@ident` of the form :n:`@qualid {+ @term} = @term` or :n:`@term = @qualid {+ @term}` where :n:`@qualid` must have been defined using Function (see -:ref:`TODO-2.3-advancedrecursivefunctions`). Note that this tactic is only +:ref:`advanced-recursive-functions`). Note that this tactic is only available after a ``Require Import FunInd``. @@ -4077,7 +4081,7 @@ This kind of inversion has nothing to do with the tactic :tacn:`inversion` above. This tactic does :g:`change (@ident t)`, where `t` is a term built in order to ensure the convertibility. In other words, it does inversion of the function :n:`@ident`. This function must be a fixpoint on a simple recursive -datatype: see :ref:`TODO-10.3-quote` for the full details. +datatype: see :ref:`quote` for the full details. .. exn:: quote: not a simple fixpoint @@ -4109,6 +4113,8 @@ using the ``Require Import`` command. Use ``classical_right`` to prove the right part of the disjunction with the assumption that the negation of left part holds. +.. _tactics-automatizing: + Automatizing ------------ @@ -4148,7 +4154,7 @@ formulas built with `~`, `\/`, `/\`, `->` on top of equalities, inequalities and disequalities on both the type :g:`nat` of natural numbers and :g:`Z` of binary integers. This tactic must be loaded by the command ``Require Import Omega``. See the additional documentation about omega -(see Chapter :ref:`TODO-21-omega`). +(see Chapter :ref:`omega`). .. tacn:: ring @@ -4168,7 +4174,7 @@ given in the conclusion of the goal by their normal forms. If no term is given, then the conclusion should be an equation and both hand sides are normalized. -See :ref:`TODO-Chapter-25-Theringandfieldtacticfamilies` for more information on +See :ref:`Theringandfieldtacticfamilies` for more information on the tactic and how to declare new ring structures. All declared field structures can be printed with the ``Print Rings`` command. @@ -4194,7 +4200,7 @@ denominators. So it produces an equation without division nor inverse. All of these 3 tactics may generate a subgoal in order to prove that denominators are different from zero. -See :ref:`TODO-Chapter-25-Theringandfieldtacticfamilies` for more information on the tactic and how to +See :ref:`Theringandfieldtacticfamilies` for more information on the tactic and how to declare new field structures. All declared field structures can be printed with the Print Fields command. @@ -4334,11 +4340,11 @@ A simple example has more value than a long explanation: The tactics macros are synchronous with the Coq section mechanism: a tactic definition is deleted from the current environment when you -close the section (see also :ref:`TODO-2.4Sectionmechanism`) where it was +close the section (see also :ref:`section-mechanism`) where it was defined. If you want that a tactic macro defined in a module is usable in the modules that require it, you should put it outside of any section. -:ref:`TODO-9-Thetacticlanguage` gives examples of more complex +:ref:`ltac` gives examples of more complex user-defined tactics. .. [1] Actually, only the second subgoal will be generated since the diff --git a/doc/sphinx/proof-engine/vernacular-commands.rst b/doc/sphinx/proof-engine/vernacular-commands.rst index 0bb6eea23..da4034fb8 100644 --- a/doc/sphinx/proof-engine/vernacular-commands.rst +++ b/doc/sphinx/proof-engine/vernacular-commands.rst @@ -77,10 +77,11 @@ section. Flags, Options and Tables ----------------------------- -|Coq| configurability is based on flags (e.g. Set Printing All in -Section :ref:`TODO-2.9-printing-full`), options (e.g. ``Set Printing Widthinteger`` in Section -:ref:`TODO-6.9.6-set-printing-width`), or tables (e.g. ``Add Printing Record ident``, in Section -:ref:`TODO-2.2.4-add-printing-record`). The names of flags, options and tables are made of non-empty sequences of identifiers +|Coq| configurability is based on flags (e.g. ``Set Printing All`` in +Section :ref:`printing_constructions_full`), options (e.g. ``Set Printing Widthinteger`` in Section +:ref:`controlling-display`), or tables (e.g. ``Add Printing Record ident``, in Section +:ref:`record-types`). +The names of flags, options and tables are made of non-empty sequences of identifiers (conventionally with capital initial letter). The general commands handling flags, options and tables are given below. @@ -95,7 +96,6 @@ when the current module ends. Variants: - .. cmdv:: Local Set @flag. This command switches :n:`@flag` on. The original state @@ -228,7 +228,7 @@ Variants: .. cmdv:: @selector: Check @term. specifies on which subgoal to perform typing -(see Section :ref:`TODO-8.1-invocation-of-tactics`). +(see Section :ref:`invocation-of-tactics`). .. TODO : convtactic is not a syntax entry @@ -240,7 +240,7 @@ hypothesis introduced in the first subgoal (if a proof is in progress). -See also: Section :ref:`TODO-8.7-performing-computations`. +See also: Section :ref:`performingcomputations`. .. cmd:: Compute @term. @@ -250,7 +250,7 @@ bytecode-based virtual machine. It is a shortcut for ``Eval vm_compute in`` :n:`@term`. -See also: Section :ref:`TODO-8.7-performing-computations`. +See also: Section :ref:`performingcomputations`. .. cmd::Extraction @term. @@ -258,7 +258,7 @@ See also: Section :ref:`TODO-8.7-performing-computations`. This command displays the extracted term from :n:`@term`. The extraction is processed according to the distinction between ``Set`` and ``Prop``; that is to say, between logical and computational content (see Section -:ref:`TODO-4.1.1-sorts`). The extracted term is displayed in OCaml +:ref:`sorts`). The extracted term is displayed in OCaml syntax, where global identifiers are still displayed as in |Coq| terms. @@ -272,7 +272,7 @@ Recursively extracts all the material needed for the extraction of the qualified identifiers. -See also: Chapter ref:`TODO-23-chapter-extraction`. +See also: Chapter :ref:`extraction`. .. cmd:: Print Assumptions @qualid. @@ -326,13 +326,13 @@ displays the name and type of all objects (theorems, axioms, etc) of the current context whose name contains string. If string is a notation’s string denoting some reference :n:`@qualid` (referred to by its main symbol as in `"+"` or by its notation’s string as in `"_ + _"` or -`"_ 'U' _"`, see Section :ref:`TODO-12.1-notations`), the command works like ``Search`` :n:`@qualid`. +`"_ 'U' _"`, see Section :ref:`notations`), the command works like ``Search`` :n:`@qualid`. .. cmdv:: Search @string%@key. The string string must be a notation or the main symbol of a notation which is then interpreted in the scope bound to -the delimiting key :n:`@key` (see Section :ref:`TODO-12.2.2-local-interpretation-rules-for-notations`). +the delimiting key :n:`@key` (see Section :ref:`LocalInterpretationRulesForNotations`). .. cmdv:: Search @term_pattern. @@ -364,7 +364,7 @@ This restricts the search to constructions not defined in the modules named by t .. cmdv:: @selector: Search [-]@term_pattern_string … [-]@term_pattern_string. This specifies the goal on which to search hypothesis (see -Section :ref:`TODO-8.1-invocation-of-tactics`). +Section :ref:`invocation-of-tactics`). By default the 1st goal is searched. This variant can be combined with other variants presented here. @@ -382,11 +382,11 @@ be combined with other variants presented here. Search (?x * _ + ?x * _)%Z outside OmegaLemmas. .. note:: Up to |Coq| version 8.4, ``Search`` had the behavior of current -``SearchHead`` and the behavior of current Search was obtained with -command ``SearchAbout``. For compatibility, the deprecated name -SearchAbout can still be used as a synonym of Search. For -compatibility, the list of objects to search when using ``SearchAbout`` -may also be enclosed by optional[ ] delimiters. + ``SearchHead`` and the behavior of current Search was obtained with + command ``SearchAbout``. For compatibility, the deprecated name + SearchAbout can still be used as a synonym of Search. For + compatibility, the list of objects to search when using ``SearchAbout`` + may also be enclosed by optional ``[ ]`` delimiters. .. cmd:: SearchHead @term. @@ -420,12 +420,12 @@ Error messages: .. exn:: Module/section @qualid not found No module :n:`@qualid` has been required -(see Section :ref:`TODO-6.5.1-require`). +(see Section :ref:`compiled-files`). .. cmdv:: @selector: SearchHead @term. This specifies the goal on which to -search hypothesis (see Section :ref:`TODO-8.1-invocation-of-tactics`). +search hypothesis (see Section :ref:`invocation-of-tactics`). By default the 1st goal is searched. This variant can be combined with other variants presented here. @@ -479,7 +479,7 @@ This restricts the search to constructions not defined in the modules named by t .. cmdv:: @selector: SearchPattern @term. This specifies the goal on which to -search hypothesis (see Section :ref:`TODO-8.1-invocation-of-tactics`). By default the 1st goal is +search hypothesis (see Section :ref:`invocation-of-tactics`). By default the 1st goal is searched. This variant can be combined with other variants presented here. @@ -514,7 +514,7 @@ This restricts the search to constructions not defined in the modules named by t .. cmdv:: @selector: SearchRewrite @term. This specifies the goal on which to -search hypothesis (see Section :ref:`TODO-8.1-invocation-of-tactics`). By default the 1st goal is +search hypothesis (see Section :ref:`invocation-of-tactics`). By default the 1st goal is searched. This variant can be combined with other variants presented here. @@ -569,7 +569,7 @@ As Locate but restricted to modules. As Locate but restricted to tactics. -See also: Section :ref:`TODO-12.1.10-LocateSymbol` +See also: Section :ref:`locating-notations` .. _loading-files: @@ -589,7 +589,7 @@ toplevel. This kind of file is called a *script* for |Coq|. The standard This command loads the file named :n:`ident`.v, searching successively in each of the directories specified in the *loadpath*. (see Section -:ref:`TODO-2.6.3-libraries-and-filesystem`) +:ref:`libraries-and-filesystem`) Files loaded this way cannot leave proofs open, and the ``Load`` command cannot be used inside a proof either. @@ -610,7 +610,7 @@ will use the default extension ``.v``. Display, while loading, the answers of |Coq| to each command (including tactics) contained in -the loaded file See also: Section :ref:`TODO-6.9.1-silent`. +the loaded file See also: Section :ref:`controlling-display`. Error messages: @@ -626,7 +626,7 @@ Compiled files ------------------ This section describes the commands used to load compiled files (see -Chapter :ref:`TODO-14-coq-commands` for documentation on how to compile a file). A compiled +Chapter :ref:`thecoqcommands` for documentation on how to compile a file). A compiled file is a particular case of module called *library file*. @@ -644,7 +644,7 @@ replayed nor rechecked. To locate the file in the file system, :n:`@qualid` is decomposed under the form `dirpath.ident` and the file `ident.vo` is searched in the physical directory of the file system that is mapped in |Coq| loadpath to the -logical path dirpath (see Section :ref:`TODO-2.6.3-libraries-and-filesystem`). The mapping between +logical path dirpath (see Section :ref:`libraries-and-filesystem`). The mapping between physical directories and logical names at the time of requiring the file must be consistent with the mapping used to compile the file. If several files match, one of them is picked in an unspecified fashion. @@ -656,7 +656,7 @@ Variants: This loads and declares the module :n:`@qualid` and its dependencies then imports the contents of :n:`@qualid` as described -in Section :ref:`TODO-2.5.8-import`.It does not import the modules on which +:ref:`here <import_qualid>`. It does not import the modules on which qualid depends unless these modules were themselves required in module :n:`@qualid` using ``Require Export``, as described below, or recursively required @@ -696,7 +696,7 @@ Error messages: The command did not find the file foo.vo. Either foo.v exists but is not compiled or foo.vo is in a -directory which is not in your LoadPath (see Section :ref:`TODO-2.6.3-libraries-and-filesystem`). +directory which is not in your LoadPath (see Section :ref:`libraries-and-filesystem`). .. exn:: Compiled library ident.vo makes inconsistent assumptions over library qualid @@ -725,12 +725,12 @@ the time it was compiled. This command is not allowed inside a module or a module type being defined. It is meant to describe a dependency between compilation units. Note however -that the commands Import and Export alone can be used inside modules -(see Section :ref:`TODO-2.5.8-import`). +that the commands ``Import`` and ``Export`` alone can be used inside modules +(see Section :ref:`Import <import_qualid>`). -See also: Chapter :ref:`TODO-14-coq-commands` +See also: Chapter :ref:`thecoqcommands` .. cmd:: Print Libraries. @@ -746,8 +746,8 @@ This commands loads the OCaml compiled files with names given by the :n:`@string` sequence (dynamic link). It is mainly used to load tactics dynamically. The files are searched into the current OCaml loadpath (see the -command ``Add ML Path`` in Section :ref:`TODO-2.6.3-libraries-and-filesystem`). Loading of OCaml files is only possible under the bytecode version of ``coqtop`` (i.e. -``coqtop`` called with option ``-byte``, see chapter :ref:`TODO-14-coq-commands`), or when |Coq| has been compiled with a +command ``Add ML Path`` in Section :ref:`libraries-and-filesystem`). Loading of OCaml files is only possible under the bytecode version of ``coqtop`` (i.e. +``coqtop`` called with option ``-byte``, see chapter :ref:`thecoqcommands`), or when |Coq| has been compiled with a version of OCaml that supports native Dynlink (≥ 3.11). @@ -774,7 +774,7 @@ Error messages: This prints the name of all OCaml modules loaded with ``Declare ML Module``. To know from where these module were loaded, the user -should use the command Locate File (see Section :ref:`TODO-6.6.10-locate-file`) +should use the command ``Locate File`` (see :ref:`here <locate-file>`) .. _loadpath: @@ -783,7 +783,7 @@ Loadpath ------------ Loadpaths are preferably managed using |Coq| command line options (see -Section `2.6.3-libraries-and-filesystem`) but there remain vernacular commands to manage them +Section `libraries-and-filesystem`) but there remain vernacular commands to manage them for practical purposes. Such commands are only meant to be issued in the toplevel, and using them in source files is discouraged. @@ -862,14 +862,14 @@ the paths that extend the :n:`@dirpath` prefix. .. cmd:: Add ML Path @string. This command adds the path :n:`@string` to the current OCaml -loadpath (see the command `Declare ML Module`` in Section :ref:`TODO-6.5-compiled-files`). +loadpath (see the command `Declare ML Module`` in Section :ref:`compiled-files`). .. cmd:: Add Rec ML Path @string. This command adds the directory :n:`@string` and all its subdirectories to the current OCaml loadpath (see the command ``Declare ML Module`` -in Section :ref:`TODO-6.5-compiled-files`). +in Section :ref:`compiled-files`). .. cmd:: Print ML Path @string. @@ -877,8 +877,9 @@ in Section :ref:`TODO-6.5-compiled-files`). This command displays the current OCaml loadpath. This command makes sense only under the bytecode version of ``coqtop``, i.e. using option ``-byte`` -(see the command Declare ML Module in Section :ref:`TODO-6.5-compiled-files`). +(see the command Declare ML Module in Section :ref:`compiled-files`). +.. _locate-file: .. cmd:: Locate File @string. @@ -929,7 +930,7 @@ of the interactive session. This commands undoes all the effects of the last vernacular command. Commands read from a vernacular file via a ``Load`` are considered as a single command. Proof management commands are also handled by this -command (see Chapter :ref:`TODO-7-proof-handling`). For that, Back may have to undo more than +command (see Chapter :ref:`proofhandling`). For that, Back may have to undo more than one command in order to reach a state where the proof management information is available. For instance, when the last command is a ``Qed``, the management information about the closed proof has been @@ -978,9 +979,9 @@ three numbers represent the following: + *first number* : State label to reach, as for BackTo. + *second number* : *Proof state number* to unbury once aborts have been done. - |Coq| will compute the number of Undo to perform (see Chapter :ref:`TODO-7-proof-handling`). + |Coq| will compute the number of Undo to perform (see Chapter :ref:`proofhandling`). + *third number* : Number of Abort to perform, i.e. the number of currently - opened nested proofs that must be canceled (see Chapter :ref:`TODO-7-proof-handling`). + opened nested proofs that must be canceled (see Chapter :ref:`proofhandling`). @@ -1035,10 +1036,10 @@ Warnings: #. It only works with the bytecode version of |Coq| (i.e. `coqtop.byte`, - see Section `TODO-14.1-interactive-use`). + see Section `interactive-use`). #. You must have compiled |Coq| from the source package and set the environment variable COQTOP to the root of your copy of the sources - (see Section `14.3.2-customization-by-envionment-variables`). + (see Section `customization-by-environment-variables`). @@ -1108,7 +1109,7 @@ This command turns off the normal displaying. This command turns the normal display on. -TODO : check that spaces are handled well +.. todo:: check that spaces are handled well .. cmd:: Set Warnings ‘‘(@ident {* , @ident } )’’. @@ -1196,7 +1197,7 @@ This command displays the current state of compaction of goal. This command resets the displaying of goals to focused goals only (default). Unfocused goals are created by focusing other goals with -bullets (see :ref:`TODO-7.2.7-bullets`) or curly braces (see `7.2.6-curly-braces`). +bullets (see :ref:`bullets`) or curly braces (see `here <curly-braces>`). .. cmd:: Set Printing Unfocused. @@ -1221,6 +1222,7 @@ when -emacs is passed. This command disables the printing of the “(dependent evars: …)” line when -emacs is passed. +.. _vernac-controlling-the-reduction-strategies: Controlling the reduction strategies and the conversion algorithm ---------------------------------------------------------------------- @@ -1249,14 +1251,14 @@ a constant is replacing it by its definition). ``Opaque`` has also an effect on the conversion algorithm of |Coq|, telling it to delay the unfolding of a constant as much as possible when |Coq| -has to check the conversion (see Section :ref:`TODO-4.3-conversion-rules`) of two distinct +has to check the conversion (see Section :ref:`conversion-rules`) of two distinct applied constants. The scope of ``Opaque`` is limited to the current section, or current file, unless the variant ``Global Opaque`` is used. -See also: sections :ref:`TODO-8.7-performing-computations`, :ref:`TODO-8.16-automatizing`, :ref:`TODO-7.1-switching-on-off-proof-editing-mode` +See also: sections :ref:`performingcomputations`, :ref:`tactics-automatizing`, :ref:`proof-editing-mode` Error messages: @@ -1294,8 +1296,9 @@ There is no constant referred by :n:`@qualid` in the environment. -See also: sections :ref:`TODO-8.7-performing-computations`, :ref:`TODO-8.16-automatizing`, :ref:`TODO-7.1-switching-on-off-proof-editing-mode` +See also: sections :ref:`performingcomputations`, :ref:`tactics-automatizing`, :ref:`proof-editing-mode` +.. _vernac-strategy: .. cmd:: Strategy @level [ {+ @qualid } ]. @@ -1367,7 +1370,7 @@ nothing prevents the user to also perform a ``Ltac`` `ident` ``:=`` `convtactic`. -See also: sections :ref:`TODO-8.7-performing-computations` +See also: sections :ref:`performingcomputations` .. _controlling-locality-of-commands: @@ -1387,23 +1390,22 @@ scope of their effect. There are four kinds of commands: section and the module or library file they occur in. For these commands, the Local modifier limits the effect of the command to the current section or module it occurs in. As an example, the ``Coercion`` - (see Section :ref:`TODO-2.8-coercions`) and ``Strategy`` (see Section :ref:`TODO-6.10.3-strategy`) commands belong - to this category. + (see Section :ref:`coercions`) and ``Strategy`` (see :ref:`here <vernac-strategy>`) + commands belong to this category. + Commands whose default behavior is to stop their effect at the end - of the section they occur in but to extent their effect outside the - module or library file they occur in. For these commands, the Local - modifier limits the effect of the command to the current module if the - command does not occur in a section and the Global modifier extends - the effect outside the current sections and current module if the - command occurs in a section. As an example, the ``Implicit Arguments`` (see - Section :ref:`TODO-2.7-implicit-arguments`), Ltac (see Chapter :ref:`TODO-9-tactic-language`) or ``Notation`` (see Section - :ref:`TODO-12.1-notations`) commands belong to this category. Notice that a subclass of - these commands do not support extension of their scope outside - sections at all and the Global is not applicable to them. + of the section they occur in but to extent their effect outside the module or + library file they occur in. For these commands, the Local modifier limits the + effect of the command to the current module if the command does not occur in a + section and the Global modifier extends the effect outside the current + sections and current module if the command occurs in a section. As an example, + the :cmd:`Implicit Arguments`, :cmd:`Ltac` or :cmd:`Notation` commands belong + to this category. Notice that a subclass of these commands do not support + extension of their scope outside sections at all and the Global is not + applicable to them. + Commands whose default behavior is to stop their effect at the end of the section or module they occur in. For these commands, the Global modifier extends their effect outside the sections and modules they - occurs in. The ``Transparent`` and ``Opaque`` (see Section :ref:`TODO-6.10-opaque`) commands belong to this category. + occurs in. The ``Transparent`` and ``Opaque`` (see Section :ref:`vernac-controlling-the-reduction-strategies`) commands belong to this category. + Commands whose default behavior is to extend their effect outside sections but not outside modules when they occur in a section and to extend their effect outside the module or library file they occur in diff --git a/doc/sphinx/replaces.rst b/doc/sphinx/replaces.rst index 1b2e17221..28a04f90c 100644 --- a/doc/sphinx/replaces.rst +++ b/doc/sphinx/replaces.rst @@ -35,7 +35,9 @@ .. |ident_n,1| replace:: `ident`\ :math:`_{n,1}` .. |ident_n,k_n| replace:: `ident`\ :math:`_{n,k_n}` .. |ident_n| replace:: `ident`\ :math:`_{n}` +.. |Latex| replace:: :smallcaps:`LaTeX` .. |L_tac| replace:: `L`:sub:`tac` +.. |Ltac| replace:: `L`:sub:`tac` .. |ML| replace:: :smallcaps:`ML` .. |mod_0| replace:: `mod`\ :math:`_{0}` .. |mod_1| replace:: `mod`\ :math:`_{1}` @@ -54,7 +56,7 @@ .. |module_type_n| replace:: `module_type`\ :math:`_{n}` .. |N| replace:: ``N`` .. |nat| replace:: ``nat`` -.. |Ocaml| replace:: :smallcaps:`OCaml` +.. |OCaml| replace:: :smallcaps:`OCaml` .. |p_1| replace:: `p`\ :math:`_{1}` .. |p_i| replace:: `p`\ :math:`_{i}` .. |p_n| replace:: `p`\ :math:`_{n}` diff --git a/doc/sphinx/user-extensions/proof-schemes.rst b/doc/sphinx/user-extensions/proof-schemes.rst index 583b73e53..8a24a382a 100644 --- a/doc/sphinx/user-extensions/proof-schemes.rst +++ b/doc/sphinx/user-extensions/proof-schemes.rst @@ -3,6 +3,8 @@ Proof schemes =============== +.. _proofschemes-induction-principles: + Generation of induction principles with ``Scheme`` -------------------------------------------------------- @@ -106,11 +108,10 @@ induction principles when defining a new inductive type with the ``Unset Elimination Schemes`` command. It may be reactivated at any time with ``Set Elimination Schemes``. -The types declared with the keywords ``Variant`` (see :ref:`TODO-1.3.3`) and ``Record`` -(see :ref:`Record Types <record-types>`) do not have an automatic declaration of the induction -principles. It can be activated with the command -``Set Nonrecursive Elimination Schemes``. It can be deactivated again with -``Unset Nonrecursive Elimination Schemes``. +.. opt:: Nonrecursive Elimination Schemes + +This option controls whether types declared with the keywords :cmd:`Variant` and +:cmd:`Record` get an automatic declaration of the induction principles. In addition, the ``Case Analysis Schemes`` flag governs the generation of case analysis lemmas for inductive types, i.e. corresponding to the @@ -163,6 +164,8 @@ concluded by the conjunction of their conclusions. Check tree_forest_mutind. +.. _functional-scheme: + Generation of induction principles with ``Functional`` ``Scheme`` ----------------------------------------------------------------- @@ -229,7 +232,7 @@ definition written by the user. simpl; auto with arith. Qed. - We can use directly the functional induction (:ref:`TODO-8.5.5`) tactic instead + We can use directly the functional induction (:tacn:`function induction`) tactic instead of the pattern/apply trick: .. coqtop:: all @@ -305,6 +308,8 @@ definition written by the user. .. coqtop:: all Check tree_size_ind2. + +.. _derive-inversion: Generation of inversion principles with ``Derive`` ``Inversion`` ----------------------------------------------------------------- diff --git a/doc/sphinx/user-extensions/syntax-extensions.rst b/doc/sphinx/user-extensions/syntax-extensions.rst index 531295b63..9965d5002 100644 --- a/doc/sphinx/user-extensions/syntax-extensions.rst +++ b/doc/sphinx/user-extensions/syntax-extensions.rst @@ -345,13 +345,13 @@ inductive type or a recursive constant and a notation for it. Simultaneous definition of terms and notations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Thanks to reserved notations, the inductive, co-inductive, record, recursive -and corecursive definitions can benefit of customized notations. To do -this, insert a ``where`` notation clause after the definition of the -(co)inductive type or (co)recursive term (or after the definition of -each of them in case of mutual definitions). The exact syntax is given -on Figure 12.1 for inductive, co-inductive, recursive and corecursive -definitions and on Figure :ref:`record-syntax` for records. Here are examples: +Thanks to reserved notations, the inductive, co-inductive, record, recursive and +corecursive definitions can benefit of customized notations. To do this, insert +a ``where`` notation clause after the definition of the (co)inductive type or +(co)recursive term (or after the definition of each of them in case of mutual +definitions). The exact syntax is given by :token:`decl_notation` for inductive, +co-inductive, recursive and corecursive definitions and in :ref:`record-types` +for records. Here are examples: .. coqtop:: in @@ -381,23 +381,21 @@ Displaying informations about notations :opt:`Printing All` To disable other elements in addition to notations. +.. _locating-notations: + Locating notations ~~~~~~~~~~~~~~~~~~ -.. cmd:: Locate @symbol - - To know to which notations a given symbol belongs to, use the command - ``Locate symbol``, where symbol is any (composite) symbol surrounded by double - quotes. To locate a particular notation, use a string where the variables of the - notation are replaced by “_” and where possible single quotes inserted around - identifiers or tokens starting with a single quote are dropped. - - .. coqtop:: all +To know to which notations a given symbol belongs to, use the :cmd:`Locate` +command. You can call it on any (composite) symbol surrounded by double quotes. +To locate a particular notation, use a string where the variables of the +notation are replaced by “_” and where possible single quotes inserted around +identifiers or tokens starting with a single quote are dropped. - Locate "exists". - Locate "exists _ .. _ , _". +.. coqtop:: all - .. todo:: See also: Section 6.3.10. + Locate "exists". + Locate "exists _ .. _ , _". Notations and binders ~~~~~~~~~~~~~~~~~~~~~ @@ -435,8 +433,7 @@ Binders bound in the notation and parsed as patterns In the same way as patterns can be used as binders, as in :g:`fun '(x,y) => x+y` or :g:`fun '(existT _ x _) => x`, notations can be -defined so that any pattern (in the sense of the entry :n:`@pattern` of -Figure :ref:`term-syntax-aux`) can be used in place of the +defined so that any :n:`@pattern` can be used in place of the binder. Here is an example: .. coqtop:: in reset @@ -475,7 +472,7 @@ variable. Here is an example showing the difference: The default level for a ``pattern`` is 0. One can use a different level by using ``pattern at level`` :math:`n` where the scale is the same as the one for -terms (Figure :ref:`init-notations`). +terms (see :ref:`init-notations`). Binders bound in the notation and parsed as terms +++++++++++++++++++++++++++++++++++++++++++++++++ @@ -491,7 +488,7 @@ the following: This is so because the grammar also contains rules starting with :g:`{}` and followed by a term, such as the rule for the notation :g:`{ A } + { B }` for the -constant :g:`sumbool` (see Section :ref:`sumbool`). +constant :g:`sumbool` (see Section :ref:`specification`). Then, in the rule, ``x ident`` is replaced by ``x at level 99 as ident`` meaning that ``x`` is parsed as a term at level 99 (as done in the notation for @@ -829,6 +826,8 @@ lonely notations. These scopes, in opening order, are ``core_scope``, These variants survive sections. They behave as if Global were absent when not inside a section. +.. _LocalInterpretationRulesForNotations: + Local interpretation rules for notations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -859,6 +858,7 @@ Binding arguments of a constant to an interpretation scope +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .. cmd:: Arguments @qualid {+ @name%@scope} + :name: Arguments (scopes) It is possible to set in advance that some arguments of a given constant have to be interpreted in a given scope. The command is @@ -897,7 +897,7 @@ Binding arguments of a constant to an interpretation scope .. cmdv:: Arguments @qualid {+ @name%scope} : extra scopes Defines extra argument scopes, to be used in case of coercion to Funclass - (see Chapter :ref:`Coercions-full`) or with a computed type. + (see Chapter :ref:`implicitcoercions`) or with a computed type. .. cmdv:: Global Arguments @qualid {+ @name%@scope} @@ -957,7 +957,7 @@ Binding types of arguments to an interpretation scope type :g:`t` in :g:`f t a` is not recognized as an argument to be interpreted in scope ``scope``. - More generally, any coercion :n:`@class` (see Chapter :ref:`Coercions-full`) + More generally, any coercion :n:`@class` (see Chapter :ref:`implicitcoercions`) can be bound to an interpretation scope. The command to do it is :n:`Bind Scope @scope with @class` diff --git a/doc/tools/coqrst/coqdomain.py b/doc/tools/coqrst/coqdomain.py index 663ab9d37..f09ed4b55 100644 --- a/doc/tools/coqrst/coqdomain.py +++ b/doc/tools/coqrst/coqdomain.py @@ -108,7 +108,7 @@ class CoqObject(ObjectDescription): annotation = self.annotation + ' ' signode += addnodes.desc_annotation(annotation, annotation) self._render_signature(signature, signode) - return self._name_from_signature(signature) + return self.options.get("name") or self._name_from_signature(signature) @property def _index_suffix(self): @@ -145,14 +145,6 @@ class CoqObject(ObjectDescription): index_text = name + self._index_suffix self.indexnode['entries'].append(('single', index_text, target, '', None)) - def run(self): - """Small extension of the parent's run method, handling user-provided names.""" - [idx, node] = super().run() - custom_name = self.options.get("name") - if custom_name: - self.add_target_and_index(custom_name, "", node.children[0]) - return [idx, node] - def add_target_and_index(self, name, _, signode): """Create a target and an index entry for name""" if name: @@ -194,13 +186,18 @@ class VernacObject(NotationObject): annotation = "Command" def _name_from_signature(self, signature): - return stringify_with_ellipses(signature) + m = re.match(r"[a-zA-Z ]+", signature) + if m: + return m.group(0).strip() class VernacVariantObject(VernacObject): """An object to represent variants of Coq commands""" index_suffix = "(cmdv)" annotation = "Variant" + def _name_from_signature(self, signature): + return None + class TacticNotationObject(NotationObject): """An object to represent Coq tactic notations""" subdomain = "tacn" diff --git a/doc/tools/coqrst/notations/CoqNotations.ttf b/doc/tools/coqrst/notations/CoqNotations.ttf Binary files differnew file mode 100644 index 000000000..da8f2850d --- /dev/null +++ b/doc/tools/coqrst/notations/CoqNotations.ttf diff --git a/doc/tools/coqrst/notations/TacticNotations.g b/doc/tools/coqrst/notations/TacticNotations.g index 68658fe49..a889ebda7 100644 --- a/doc/tools/coqrst/notations/TacticNotations.g +++ b/doc/tools/coqrst/notations/TacticNotations.g @@ -20,13 +20,14 @@ repeat: LGROUP (ATOM)? WHITESPACE blocks (WHITESPACE)? RBRACE; curlies: LBRACE (whitespace)? blocks (whitespace)? RBRACE; whitespace: WHITESPACE; meta: METACHAR; -atomic: ATOM; -hole: ID; +atomic: ATOM (SUB)?; +hole: ID (SUB)?; LGROUP: '{' [+*?]; LBRACE: '{'; RBRACE: '}'; METACHAR: '%' [|(){}]; -ATOM: '@' | ~[@{} ]+; -ID: '@' [a-zA-Z0-9_]+; +ATOM: '@' | '_' | ~[@_{} ]+; +ID: '@' ('_'? [a-zA-Z0-9])+; +SUB: '_' '_' [a-zA-Z0-9]+; WHITESPACE: ' '+; diff --git a/doc/tools/coqrst/notations/TacticNotations.tokens b/doc/tools/coqrst/notations/TacticNotations.tokens index 76ed2b065..88b38f97a 100644 --- a/doc/tools/coqrst/notations/TacticNotations.tokens +++ b/doc/tools/coqrst/notations/TacticNotations.tokens @@ -4,6 +4,7 @@ RBRACE=3 METACHAR=4 ATOM=5 ID=6 -WHITESPACE=7 +SUB=7 +WHITESPACE=8 '{'=2 '}'=3 diff --git a/doc/tools/coqrst/notations/TacticNotationsLexer.py b/doc/tools/coqrst/notations/TacticNotationsLexer.py index 61d8d2f9e..27293e7e0 100644 --- a/doc/tools/coqrst/notations/TacticNotationsLexer.py +++ b/doc/tools/coqrst/notations/TacticNotationsLexer.py @@ -7,24 +7,28 @@ import sys def serializedATN(): with StringIO() as buf: - buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\t") - buf.write(".\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7") - buf.write("\4\b\t\b\3\2\3\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5\3\5\3\6\3") - buf.write("\6\6\6\36\n\6\r\6\16\6\37\5\6\"\n\6\3\7\3\7\6\7&\n\7\r") - buf.write("\7\16\7\'\3\b\6\b+\n\b\r\b\16\b,\2\2\t\3\3\5\4\7\5\t\6") - buf.write("\13\7\r\b\17\t\3\2\6\4\2,-AA\4\2*+}\177\6\2\"\"BB}}\177") - buf.write("\177\6\2\62;C\\aac|\2\61\2\3\3\2\2\2\2\5\3\2\2\2\2\7\3") - buf.write("\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2\17\3\2\2") - buf.write("\2\3\21\3\2\2\2\5\24\3\2\2\2\7\26\3\2\2\2\t\30\3\2\2\2") - buf.write("\13!\3\2\2\2\r#\3\2\2\2\17*\3\2\2\2\21\22\7}\2\2\22\23") - buf.write("\t\2\2\2\23\4\3\2\2\2\24\25\7}\2\2\25\6\3\2\2\2\26\27") - buf.write("\7\177\2\2\27\b\3\2\2\2\30\31\7\'\2\2\31\32\t\3\2\2\32") - buf.write("\n\3\2\2\2\33\"\7B\2\2\34\36\n\4\2\2\35\34\3\2\2\2\36") - buf.write("\37\3\2\2\2\37\35\3\2\2\2\37 \3\2\2\2 \"\3\2\2\2!\33\3") - buf.write("\2\2\2!\35\3\2\2\2\"\f\3\2\2\2#%\7B\2\2$&\t\5\2\2%$\3") - buf.write("\2\2\2&\'\3\2\2\2\'%\3\2\2\2\'(\3\2\2\2(\16\3\2\2\2)+") - buf.write("\7\"\2\2*)\3\2\2\2+,\3\2\2\2,*\3\2\2\2,-\3\2\2\2-\20\3") - buf.write("\2\2\2\7\2\37!\',\2") + buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\n") + buf.write(":\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7") + buf.write("\4\b\t\b\4\t\t\t\3\2\3\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5\3") + buf.write("\5\3\6\3\6\6\6 \n\6\r\6\16\6!\5\6$\n\6\3\7\3\7\5\7(\n") + buf.write("\7\3\7\6\7+\n\7\r\7\16\7,\3\b\3\b\3\b\6\b\62\n\b\r\b\16") + buf.write("\b\63\3\t\6\t\67\n\t\r\t\16\t8\2\2\n\3\3\5\4\7\5\t\6\13") + buf.write("\7\r\b\17\t\21\n\3\2\7\4\2,-AA\4\2*+}\177\4\2BBaa\7\2") + buf.write("\"\"BBaa}}\177\177\5\2\62;C\\c|\2?\2\3\3\2\2\2\2\5\3\2") + buf.write("\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2") + buf.write("\2\17\3\2\2\2\2\21\3\2\2\2\3\23\3\2\2\2\5\26\3\2\2\2\7") + buf.write("\30\3\2\2\2\t\32\3\2\2\2\13#\3\2\2\2\r%\3\2\2\2\17.\3") + buf.write("\2\2\2\21\66\3\2\2\2\23\24\7}\2\2\24\25\t\2\2\2\25\4\3") + buf.write("\2\2\2\26\27\7}\2\2\27\6\3\2\2\2\30\31\7\177\2\2\31\b") + buf.write("\3\2\2\2\32\33\7\'\2\2\33\34\t\3\2\2\34\n\3\2\2\2\35$") + buf.write("\t\4\2\2\36 \n\5\2\2\37\36\3\2\2\2 !\3\2\2\2!\37\3\2\2") + buf.write("\2!\"\3\2\2\2\"$\3\2\2\2#\35\3\2\2\2#\37\3\2\2\2$\f\3") + buf.write("\2\2\2%*\7B\2\2&(\7a\2\2\'&\3\2\2\2\'(\3\2\2\2()\3\2\2") + buf.write("\2)+\t\6\2\2*\'\3\2\2\2+,\3\2\2\2,*\3\2\2\2,-\3\2\2\2") + buf.write("-\16\3\2\2\2./\7a\2\2/\61\7a\2\2\60\62\t\6\2\2\61\60\3") + buf.write("\2\2\2\62\63\3\2\2\2\63\61\3\2\2\2\63\64\3\2\2\2\64\20") + buf.write("\3\2\2\2\65\67\7\"\2\2\66\65\3\2\2\2\678\3\2\2\28\66\3") + buf.write("\2\2\289\3\2\2\29\22\3\2\2\2\t\2!#\',\638\2") return buf.getvalue() @@ -40,7 +44,8 @@ class TacticNotationsLexer(Lexer): METACHAR = 4 ATOM = 5 ID = 6 - WHITESPACE = 7 + SUB = 7 + WHITESPACE = 8 channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ] @@ -50,10 +55,11 @@ class TacticNotationsLexer(Lexer): "'{'", "'}'" ] symbolicNames = [ "<INVALID>", - "LGROUP", "LBRACE", "RBRACE", "METACHAR", "ATOM", "ID", "WHITESPACE" ] + "LGROUP", "LBRACE", "RBRACE", "METACHAR", "ATOM", "ID", "SUB", + "WHITESPACE" ] ruleNames = [ "LGROUP", "LBRACE", "RBRACE", "METACHAR", "ATOM", "ID", - "WHITESPACE" ] + "SUB", "WHITESPACE" ] grammarFileName = "TacticNotations.g" diff --git a/doc/tools/coqrst/notations/TacticNotationsLexer.tokens b/doc/tools/coqrst/notations/TacticNotationsLexer.tokens index 76ed2b065..88b38f97a 100644 --- a/doc/tools/coqrst/notations/TacticNotationsLexer.tokens +++ b/doc/tools/coqrst/notations/TacticNotationsLexer.tokens @@ -4,6 +4,7 @@ RBRACE=3 METACHAR=4 ATOM=5 ID=6 -WHITESPACE=7 +SUB=7 +WHITESPACE=8 '{'=2 '}'=3 diff --git a/doc/tools/coqrst/notations/TacticNotationsParser.py b/doc/tools/coqrst/notations/TacticNotationsParser.py index c7e28af52..645f07897 100644 --- a/doc/tools/coqrst/notations/TacticNotationsParser.py +++ b/doc/tools/coqrst/notations/TacticNotationsParser.py @@ -7,29 +7,31 @@ import sys def serializedATN(): with StringIO() as buf: - buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\t") - buf.write("F\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b") + buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\n") + buf.write("J\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b") buf.write("\t\b\4\t\t\t\4\n\t\n\3\2\3\2\3\2\3\3\3\3\5\3\32\n\3\3") buf.write("\3\7\3\35\n\3\f\3\16\3 \13\3\3\4\3\4\3\4\3\4\3\4\5\4\'") buf.write("\n\4\3\5\3\5\5\5+\n\5\3\5\3\5\3\5\5\5\60\n\5\3\5\3\5\3") buf.write("\6\3\6\5\6\66\n\6\3\6\3\6\5\6:\n\6\3\6\3\6\3\7\3\7\3\b") - buf.write("\3\b\3\t\3\t\3\n\3\n\3\n\2\2\13\2\4\6\b\n\f\16\20\22\2") - buf.write("\2\2F\2\24\3\2\2\2\4\27\3\2\2\2\6&\3\2\2\2\b(\3\2\2\2") - buf.write("\n\63\3\2\2\2\f=\3\2\2\2\16?\3\2\2\2\20A\3\2\2\2\22C\3") - buf.write("\2\2\2\24\25\5\4\3\2\25\26\7\2\2\3\26\3\3\2\2\2\27\36") - buf.write("\5\6\4\2\30\32\5\f\7\2\31\30\3\2\2\2\31\32\3\2\2\2\32") - buf.write("\33\3\2\2\2\33\35\5\6\4\2\34\31\3\2\2\2\35 \3\2\2\2\36") - buf.write("\34\3\2\2\2\36\37\3\2\2\2\37\5\3\2\2\2 \36\3\2\2\2!\'") - buf.write("\5\20\t\2\"\'\5\16\b\2#\'\5\22\n\2$\'\5\b\5\2%\'\5\n\6") - buf.write("\2&!\3\2\2\2&\"\3\2\2\2&#\3\2\2\2&$\3\2\2\2&%\3\2\2\2") - buf.write("\'\7\3\2\2\2(*\7\3\2\2)+\7\7\2\2*)\3\2\2\2*+\3\2\2\2+") - buf.write(",\3\2\2\2,-\7\t\2\2-/\5\4\3\2.\60\7\t\2\2/.\3\2\2\2/\60") - buf.write("\3\2\2\2\60\61\3\2\2\2\61\62\7\5\2\2\62\t\3\2\2\2\63\65") - buf.write("\7\4\2\2\64\66\5\f\7\2\65\64\3\2\2\2\65\66\3\2\2\2\66") - buf.write("\67\3\2\2\2\679\5\4\3\28:\5\f\7\298\3\2\2\29:\3\2\2\2") - buf.write(":;\3\2\2\2;<\7\5\2\2<\13\3\2\2\2=>\7\t\2\2>\r\3\2\2\2") - buf.write("?@\7\6\2\2@\17\3\2\2\2AB\7\7\2\2B\21\3\2\2\2CD\7\b\2\2") - buf.write("D\23\3\2\2\2\t\31\36&*/\659") + buf.write("\3\b\3\t\3\t\5\tD\n\t\3\n\3\n\5\nH\n\n\3\n\2\2\13\2\4") + buf.write("\6\b\n\f\16\20\22\2\2\2L\2\24\3\2\2\2\4\27\3\2\2\2\6&") + buf.write("\3\2\2\2\b(\3\2\2\2\n\63\3\2\2\2\f=\3\2\2\2\16?\3\2\2") + buf.write("\2\20A\3\2\2\2\22E\3\2\2\2\24\25\5\4\3\2\25\26\7\2\2\3") + buf.write("\26\3\3\2\2\2\27\36\5\6\4\2\30\32\5\f\7\2\31\30\3\2\2") + buf.write("\2\31\32\3\2\2\2\32\33\3\2\2\2\33\35\5\6\4\2\34\31\3\2") + buf.write("\2\2\35 \3\2\2\2\36\34\3\2\2\2\36\37\3\2\2\2\37\5\3\2") + buf.write("\2\2 \36\3\2\2\2!\'\5\20\t\2\"\'\5\16\b\2#\'\5\22\n\2") + buf.write("$\'\5\b\5\2%\'\5\n\6\2&!\3\2\2\2&\"\3\2\2\2&#\3\2\2\2") + buf.write("&$\3\2\2\2&%\3\2\2\2\'\7\3\2\2\2(*\7\3\2\2)+\7\7\2\2*") + buf.write(")\3\2\2\2*+\3\2\2\2+,\3\2\2\2,-\7\n\2\2-/\5\4\3\2.\60") + buf.write("\7\n\2\2/.\3\2\2\2/\60\3\2\2\2\60\61\3\2\2\2\61\62\7\5") + buf.write("\2\2\62\t\3\2\2\2\63\65\7\4\2\2\64\66\5\f\7\2\65\64\3") + buf.write("\2\2\2\65\66\3\2\2\2\66\67\3\2\2\2\679\5\4\3\28:\5\f\7") + buf.write("\298\3\2\2\29:\3\2\2\2:;\3\2\2\2;<\7\5\2\2<\13\3\2\2\2") + buf.write("=>\7\n\2\2>\r\3\2\2\2?@\7\6\2\2@\17\3\2\2\2AC\7\7\2\2") + buf.write("BD\7\t\2\2CB\3\2\2\2CD\3\2\2\2D\21\3\2\2\2EG\7\b\2\2F") + buf.write("H\7\t\2\2GF\3\2\2\2GH\3\2\2\2H\23\3\2\2\2\13\31\36&*/") + buf.write("\659CG") return buf.getvalue() @@ -46,7 +48,7 @@ class TacticNotationsParser ( Parser ): literalNames = [ "<INVALID>", "<INVALID>", "'{'", "'}'" ] symbolicNames = [ "<INVALID>", "LGROUP", "LBRACE", "RBRACE", "METACHAR", - "ATOM", "ID", "WHITESPACE" ] + "ATOM", "ID", "SUB", "WHITESPACE" ] RULE_top = 0 RULE_blocks = 1 @@ -68,7 +70,8 @@ class TacticNotationsParser ( Parser ): METACHAR=4 ATOM=5 ID=6 - WHITESPACE=7 + SUB=7 + WHITESPACE=8 def __init__(self, input:TokenStream, output:TextIO = sys.stdout): super().__init__(input, output) @@ -502,6 +505,9 @@ class TacticNotationsParser ( Parser ): def ATOM(self): return self.getToken(TacticNotationsParser.ATOM, 0) + def SUB(self): + return self.getToken(TacticNotationsParser.SUB, 0) + def getRuleIndex(self): return TacticNotationsParser.RULE_atomic @@ -518,10 +524,19 @@ class TacticNotationsParser ( Parser ): localctx = TacticNotationsParser.AtomicContext(self, self._ctx, self.state) self.enterRule(localctx, 14, self.RULE_atomic) + self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 63 self.match(TacticNotationsParser.ATOM) + self.state = 65 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==TacticNotationsParser.SUB: + self.state = 64 + self.match(TacticNotationsParser.SUB) + + except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) @@ -539,6 +554,9 @@ class TacticNotationsParser ( Parser ): def ID(self): return self.getToken(TacticNotationsParser.ID, 0) + def SUB(self): + return self.getToken(TacticNotationsParser.SUB, 0) + def getRuleIndex(self): return TacticNotationsParser.RULE_hole @@ -555,10 +573,19 @@ class TacticNotationsParser ( Parser ): localctx = TacticNotationsParser.HoleContext(self, self._ctx, self.state) self.enterRule(localctx, 16, self.RULE_hole) + self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 65 + self.state = 67 self.match(TacticNotationsParser.ID) + self.state = 69 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==TacticNotationsParser.SUB: + self.state = 68 + self.match(TacticNotationsParser.SUB) + + except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) diff --git a/doc/tools/coqrst/notations/UbuntuMono-Square.ttf b/doc/tools/coqrst/notations/UbuntuMono-Square.ttf Binary files differdeleted file mode 100644 index a53a9a0f0..000000000 --- a/doc/tools/coqrst/notations/UbuntuMono-Square.ttf +++ /dev/null diff --git a/doc/tools/coqrst/notations/fontsupport.py b/doc/tools/coqrst/notations/fontsupport.py index 3402ea2aa..a3efd97f5 100755 --- a/doc/tools/coqrst/notations/fontsupport.py +++ b/doc/tools/coqrst/notations/fontsupport.py @@ -63,8 +63,7 @@ def trim_font(fnt): def center_glyphs(src_font_path, dst_font_path, dst_name): fnt = trim_font(fontforge.open(src_font_path)) - size = max(max(g.width for g in fnt.glyphs()), - max(glyph_height(g) for g in fnt.glyphs())) + size = max(g.width for g in fnt.glyphs()) fnt.ascent, fnt.descent = size, 0 for glyph in fnt.glyphs(): scale_single_glyph(glyph, size, size) @@ -77,5 +76,5 @@ if __name__ == '__main__': from os.path import dirname, join, abspath curdir = dirname(abspath(__file__)) ubuntumono_path = join(curdir, "UbuntuMono-B.ttf") - ubuntumono_mod_path = join(curdir, "UbuntuMono-Square.ttf") - center_glyphs(ubuntumono_path, ubuntumono_mod_path, "UbuntuMono-Square") + ubuntumono_mod_path = join(curdir, "CoqNotations.ttf") + center_glyphs(ubuntumono_path, ubuntumono_mod_path, "CoqNotations") diff --git a/doc/tools/coqrst/notations/html.py b/doc/tools/coqrst/notations/html.py index 9c94a4b2d..87a41cf9f 100644 --- a/doc/tools/coqrst/notations/html.py +++ b/doc/tools/coqrst/notations/html.py @@ -41,6 +41,9 @@ class TacticNotationsToHTMLVisitor(TacticNotationsVisitor): def visitHole(self, ctx:TacticNotationsParser.HoleContext): tags.span(ctx.ID().getText()[1:], _class="hole") + sub = ctx.SUB() + if sub: + tags.sub(sub.getText()[1:]) def visitMeta(self, ctx:TacticNotationsParser.MetaContext): txt = ctx.METACHAR().getText()[1:] diff --git a/doc/tools/coqrst/notations/sphinx.py b/doc/tools/coqrst/notations/sphinx.py index 26a5f6968..e05b83418 100644 --- a/doc/tools/coqrst/notations/sphinx.py +++ b/doc/tools/coqrst/notations/sphinx.py @@ -56,19 +56,36 @@ class TacticNotationsToSphinxVisitor(TacticNotationsVisitor): def visitAtomic(self, ctx:TacticNotationsParser.AtomicContext): atom = ctx.ATOM().getText() - return [nodes.inline(atom, atom)] + sub = ctx.SUB() + node = nodes.inline(atom, atom) + + if sub: + sub_index = sub.getText()[2:] + node += nodes.subscript(sub_index, sub_index) + + return [node] def visitHole(self, ctx:TacticNotationsParser.HoleContext): hole = ctx.ID().getText() token_name = hole[1:] node = nodes.inline(hole, token_name, classes=["hole"]) + + sub = ctx.SUB() + if sub: + sub_index = sub.getText()[2:] + node += nodes.subscript(sub_index, sub_index) + return [addnodes.pending_xref(token_name, node, reftype='token', refdomain='std', reftarget=token_name)] def visitMeta(self, ctx:TacticNotationsParser.MetaContext): meta = ctx.METACHAR().getText() metachar = meta[1:] # remove escape char token_name = metachar - return [nodes.inline(metachar, token_name, classes=["meta"])] + if (metachar == "{") or (metachar == "}"): + classes=[] + else: + classes=["meta"] + return [nodes.inline(metachar, token_name, classes=classes)] def visitWhitespace(self, ctx:TacticNotationsParser.WhitespaceContext): return [nodes.Text(" ")] diff --git a/engine/eConstr.ml b/engine/eConstr.ml index bd47a04f1..a72bdee12 100644 --- a/engine/eConstr.ml +++ b/engine/eConstr.ml @@ -13,132 +13,8 @@ open Util open Names open Constr open Context -open Evd - -module API : -sig -module ESorts : -sig -type t -val make : Sorts.t -> t -val kind : Evd.evar_map -> t -> Sorts.t -val unsafe_to_sorts : t -> Sorts.t -end -module EInstance : -sig -type t -val make : Univ.Instance.t -> t -val kind : Evd.evar_map -> t -> Univ.Instance.t -val empty : t -val is_empty : t -> bool -val unsafe_to_instance : t -> Univ.Instance.t -end -type t -val kind : Evd.evar_map -> t -> (t, t, ESorts.t, EInstance.t) Constr.kind_of_term -val kind_upto : Evd.evar_map -> constr -> (constr, types, Sorts.t, Univ.Instance.t) Constr.kind_of_term -val kind_of_type : Evd.evar_map -> t -> (t, t) Term.kind_of_type -val whd_evar : Evd.evar_map -> t -> t -val of_kind : (t, t, ESorts.t, EInstance.t) Constr.kind_of_term -> t -val of_constr : Constr.t -> t -val to_constr : evar_map -> t -> Constr.t -val unsafe_to_constr : t -> Constr.t -val unsafe_eq : (t, Constr.t) eq -val of_named_decl : (Constr.t, Constr.types) Context.Named.Declaration.pt -> (t, t) Context.Named.Declaration.pt -val unsafe_to_named_decl : (t, t) Context.Named.Declaration.pt -> (Constr.t, Constr.types) Context.Named.Declaration.pt -val unsafe_to_rel_decl : (t, t) Context.Rel.Declaration.pt -> (Constr.t, Constr.types) Context.Rel.Declaration.pt -val of_rel_decl : (Constr.t, Constr.types) Context.Rel.Declaration.pt -> (t, t) Context.Rel.Declaration.pt -val to_rel_decl : Evd.evar_map -> (t, t) Context.Rel.Declaration.pt -> (Constr.t, Constr.types) Context.Rel.Declaration.pt -end = -struct - -module ESorts = -struct - type t = Sorts.t - let make s = s - let kind sigma = function - | Sorts.Type u -> Sorts.sort_of_univ (Evd.normalize_universe sigma u) - | s -> s - let unsafe_to_sorts s = s -end - -module EInstance = -struct - type t = Univ.Instance.t - let make i = i - let kind sigma i = - if Univ.Instance.is_empty i then i - else Evd.normalize_universe_instance sigma i - let empty = Univ.Instance.empty - let is_empty = Univ.Instance.is_empty - let unsafe_to_instance t = t -end -type t = Constr.t - -let safe_evar_value sigma ev = - try Some (Evd.existential_value sigma ev) - with NotInstantiatedEvar | Not_found -> None - -let rec whd_evar sigma c = - match Constr.kind c with - | Evar ev -> - begin match safe_evar_value sigma ev with - | Some c -> whd_evar sigma c - | None -> c - end - | App (f, args) when isEvar f -> - (** Enforce smart constructor invariant on applications *) - let ev = destEvar f in - begin match safe_evar_value sigma ev with - | None -> c - | Some f -> whd_evar sigma (mkApp (f, args)) - end - | Cast (c0, k, t) when isEvar c0 -> - (** Enforce smart constructor invariant on casts. *) - let ev = destEvar c0 in - begin match safe_evar_value sigma ev with - | None -> c - | Some c -> whd_evar sigma (mkCast (c, k, t)) - end - | _ -> c - -let kind sigma c = Constr.kind (whd_evar sigma c) -let kind_upto = kind -let kind_of_type sigma c = Term.kind_of_type (whd_evar sigma c) -let of_kind = Constr.of_kind -let of_constr c = c -let unsafe_to_constr c = c -let unsafe_eq = Refl - -let rec to_constr sigma c = match Constr.kind c with -| Evar ev -> - begin match safe_evar_value sigma ev with - | Some c -> to_constr sigma c - | None -> Constr.map (fun c -> to_constr sigma c) c - end -| Sort (Sorts.Type u) -> - let u' = Evd.normalize_universe sigma u in - if u' == u then c else mkSort (Sorts.sort_of_univ u') -| Const (c', u) when not (Univ.Instance.is_empty u) -> - let u' = Evd.normalize_universe_instance sigma u in - if u' == u then c else mkConstU (c', u') -| Ind (i, u) when not (Univ.Instance.is_empty u) -> - let u' = Evd.normalize_universe_instance sigma u in - if u' == u then c else mkIndU (i, u') -| Construct (co, u) when not (Univ.Instance.is_empty u) -> - let u' = Evd.normalize_universe_instance sigma u in - if u' == u then c else mkConstructU (co, u') -| _ -> Constr.map (fun c -> to_constr sigma c) c - -let of_named_decl d = d -let unsafe_to_named_decl d = d -let of_rel_decl d = d -let unsafe_to_rel_decl d = d -let to_rel_decl sigma d = Context.Rel.Declaration.map_constr (to_constr sigma) d - -end - -include API +include Evd.MiniEConstr type types = t type constr = t @@ -381,8 +257,7 @@ let decompose_prod_n_assum sigma n c = in prodec_rec Context.Rel.empty n c -let existential_type sigma (evk, args) = - of_constr (existential_type sigma (evk, Array.map unsafe_to_constr args)) +let existential_type = Evd.existential_type let map sigma f c = match kind sigma c with | (Rel _ | Meta _ | Var _ | Sort _ | Const _ | Ind _ @@ -743,7 +618,7 @@ let universes_of_constr env sigma c = LSet.fold LSet.add (Universe.levels u) s | Evar (k, args) -> let concl = Evd.evar_concl (Evd.find sigma k) in - fold sigma aux (aux s (of_constr concl)) c + fold sigma aux (aux s concl) c | _ -> fold sigma aux s c in aux LSet.empty c @@ -901,6 +776,10 @@ let named_context e = cast_named_context (sym unsafe_eq) (named_context e) let val_of_named_context e = val_of_named_context (cast_named_context unsafe_eq e) let named_context_of_val e = cast_named_context (sym unsafe_eq) (named_context_of_val e) +let of_existential : Constr.existential -> existential = + let gen : type a b. (a,b) eq -> 'c * b array -> 'c * a array = fun Refl x -> x in + gen unsafe_eq + let lookup_rel i e = cast_rel_decl (sym unsafe_eq) (lookup_rel i e) let lookup_named n e = cast_named_decl (sym unsafe_eq) (lookup_named n e) let lookup_named_val n e = cast_named_decl (sym unsafe_eq) (lookup_named_val n e) @@ -916,7 +795,7 @@ let map_rel_context_in_env f env sign = let fresh_global ?loc ?rigid ?names env sigma reference = let (evd,t) = Evd.fresh_global ?loc ?rigid ?names env sigma reference in - evd, of_constr t + evd, t let is_global sigma gr c = Globnames.is_global gr (to_constr sigma c) @@ -928,5 +807,10 @@ let to_instance = EInstance.unsafe_to_instance let to_constr = unsafe_to_constr let to_rel_decl = unsafe_to_rel_decl let to_named_decl = unsafe_to_named_decl +let to_named_context = + let gen : type a b. (a, b) eq -> (a,a) Context.Named.pt -> (b,b) Context.Named.pt + = fun Refl x -> x + in + gen unsafe_eq let eq = unsafe_eq end diff --git a/engine/eConstr.mli b/engine/eConstr.mli index 8ee3b9050..9a5b5ec3a 100644 --- a/engine/eConstr.mli +++ b/engine/eConstr.mli @@ -13,7 +13,7 @@ open Names open Constr open Environ -type t +type t = Evd.econstr (** Type of incomplete terms. Essentially a wrapper around {!Constr.t} ensuring that {!Constr.kind} does not observe defined evars. *) @@ -68,11 +68,14 @@ val kind : Evd.evar_map -> t -> (t, t, ESorts.t, EInstance.t) Constr.kind_of_ter val kind_upto : Evd.evar_map -> Constr.t -> (Constr.t, Constr.t, Sorts.t, Univ.Instance.t) Constr.kind_of_term -val to_constr : Evd.evar_map -> t -> Constr.t -(** Returns the evar-normal form of the argument, and cast it as a theoretically - evar-free term. In practice this function does not check that the result - is actually evar-free, it is currently the duty of the caller to do so. - This might change in the future. *) +val to_constr : ?abort_on_undefined_evars:bool -> Evd.evar_map -> t -> Constr.t +(** Returns the evar-normal form of the argument. Note that this + function is supposed to be called when the original term has not + more free-evars anymore. If you need compatibility with the old + semantics, set [abort_on_undefined_evars] to [false]. + + For getting the evar-normal form of a term with evars see + {!Evarutil.nf_evar}. *) val kind_of_type : Evd.evar_map -> t -> (t, t) Term.kind_of_type @@ -287,6 +290,7 @@ val is_global : Evd.evar_map -> Globnames.global_reference -> t -> bool (** {5 Extra} *) +val of_existential : Constr.existential -> existential val of_named_decl : (Constr.t, Constr.types) Context.Named.Declaration.pt -> (t, types) Context.Named.Declaration.pt val of_rel_decl : (Constr.t, Constr.types) Context.Rel.Declaration.pt -> (t, types) Context.Rel.Declaration.pt @@ -305,6 +309,8 @@ sig val to_named_decl : (t, types) Context.Named.Declaration.pt -> (Constr.t, Constr.types) Context.Named.Declaration.pt (** Physical identity. Does not care for defined evars. *) + val to_named_context : (t, types) Context.Named.pt -> Context.Named.t + val to_sorts : ESorts.t -> Sorts.t (** Physical identity. Does not care for normalization. *) diff --git a/engine/evarutil.ml b/engine/evarutil.ml index 45760c6b4..065b42bf6 100644 --- a/engine/evarutil.ml +++ b/engine/evarutil.ml @@ -23,7 +23,8 @@ module RelDecl = Context.Rel.Declaration module NamedDecl = Context.Named.Declaration let safe_evar_value sigma ev = - try Some (Evd.existential_value sigma ev) + let ev = EConstr.of_existential ev in + try Some (EConstr.Unsafe.to_constr @@ Evd.existential_value sigma ev) with NotInstantiatedEvar | Not_found -> None (** Combinators *) @@ -44,11 +45,11 @@ let evd_comb2 f evdref x y = z let e_new_global evdref x = - EConstr.of_constr (evd_comb1 (Evd.fresh_global (Global.env())) evdref x) + evd_comb1 (Evd.fresh_global (Global.env())) evdref x let new_global evd x = let (evd, c) = Evd.fresh_global (Global.env()) evd x in - (evd, EConstr.of_constr c) + (evd, c) (****************************************************) (* Expanding/testing/exposing existential variables *) @@ -61,7 +62,7 @@ exception Uninstantiated_evar of Evar.t let rec flush_and_check_evars sigma c = match kind c with | Evar (evk,_ as ev) -> - (match existential_opt_value sigma ev with + (match existential_opt_value0 sigma ev with | None -> raise (Uninstantiated_evar evk) | Some c -> flush_and_check_evars sigma c) | _ -> Constr.map (flush_and_check_evars sigma) c @@ -72,9 +73,9 @@ let flush_and_check_evars sigma c = (** Term exploration up to instantiation. *) let kind_of_term_upto = EConstr.kind_upto -let nf_evar0 sigma t = EConstr.to_constr sigma (EConstr.of_constr t) +let nf_evar0 sigma t = EConstr.to_constr ~abort_on_undefined_evars:false sigma (EConstr.of_constr t) let whd_evar = EConstr.whd_evar -let nf_evar sigma c = EConstr.of_constr (EConstr.to_constr sigma c) +let nf_evar sigma c = EConstr.of_constr (EConstr.to_constr ~abort_on_undefined_evars:false sigma c) let j_nf_evar sigma j = { uj_val = nf_evar sigma j.uj_val; @@ -102,7 +103,8 @@ let nf_evar_map_universes evm = if Univ.LMap.is_empty subst then evm, nf_evar0 evm else let f = nf_evars_universes evm in - Evd.raw_map (fun _ -> map_evar_info f) evm, f + let f' c = EConstr.of_constr (f (EConstr.Unsafe.to_constr c)) in + Evd.raw_map (fun _ -> map_evar_info f') evm, f let nf_named_context_evar sigma ctx = Context.Named.map (nf_evar0 sigma) ctx @@ -115,7 +117,7 @@ let nf_env_evar sigma env = let rel' = nf_rel_context_evar sigma (EConstr.rel_context env) in EConstr.push_rel_context rel' (reset_with_named_context (val_of_named_context nc') env) -let nf_evar_info evc info = map_evar_info (nf_evar0 evc) info +let nf_evar_info evc info = map_evar_info (nf_evar evc) info let nf_evar_map evm = Evd.raw_map (fun _ evi -> nf_evar_info evm evi) evm @@ -414,7 +416,6 @@ let push_rel_context_to_named_context env sigma typ = let default_source = Loc.tag @@ Evar_kinds.InternalHole let restrict_evar evd evk filter ?src candidates = - let candidates = Option.map (fun l -> List.map EConstr.Unsafe.to_constr l) candidates in let evd, evk' = Evd.restrict evk filter ?candidates ?src evd in Evd.declare_future_goal evk' evd, evk' @@ -424,8 +425,6 @@ let new_pure_evar_full evd evi = (evd, evk) let new_pure_evar sign evd ?(src=default_source) ?(filter = Filter.identity) ?candidates ?(store = Store.empty) ?naming ?(principal=false) typ = - let typ = EConstr.Unsafe.to_constr typ in - let candidates = Option.map (fun l -> List.map EConstr.Unsafe.to_constr l) candidates in let default_naming = Misctypes.IntroAnonymous in let naming = Option.default default_naming naming in let name = match naming with @@ -513,7 +512,7 @@ let generalize_evar_over_rels sigma (ev,args) = List.fold_left2 (fun (c,inst as x) a d -> if isRel sigma a then (mkNamedProd_or_LetIn d c,a::inst) else x) - (EConstr.of_constr evi.evar_concl,[]) (Array.to_list args) sign + (evi.evar_concl,[]) (Array.to_list args) sign (************************************) (* Removing a dependency in an evar *) @@ -549,7 +548,8 @@ let rec check_and_clear_in_constr env evdref err ids global c = | Evar (evk,l as ev) -> if Evd.is_defined !evdref evk then (* If evk is already defined we replace it by its definition *) - let nc = Evd.existential_value !evdref ev in + let nc = Evd.existential_value !evdref (EConstr.of_existential ev) in + let nc = EConstr.Unsafe.to_constr nc in (check_and_clear_in_constr env evdref err ids global nc) else (* We check for dependencies to elements of ids in the @@ -559,8 +559,7 @@ let rec check_and_clear_in_constr env evdref err ids global c = removed *) let evi = Evd.find_undefined !evdref evk in let ctxt = Evd.evar_filtered_context evi in - let ctxt = List.map (fun d -> map_named_decl EConstr.of_constr d) ctxt in - let (rids,filter) = + let (rids,filter) = List.fold_right2 (fun h a (ri,filter) -> try @@ -586,7 +585,8 @@ let rec check_and_clear_in_constr env evdref err ids global c = try let nids = Id.Map.domain rids in let global = Id.Set.exists is_section_variable nids in - check_and_clear_in_constr env evdref (EvarTypingBreak ev) nids global (evar_concl evi) + let concl = EConstr.Unsafe.to_constr (evar_concl evi) in + check_and_clear_in_constr env evdref (EvarTypingBreak ev) nids global concl with ClearDependencyError (rid,err) -> raise (ClearDependencyError (Id.Map.find rid rids,err)) in @@ -597,7 +597,7 @@ let rec check_and_clear_in_constr env evdref err ids global c = let evd = !evdref in let (evd,_) = restrict_evar evd evk filter None in evdref := evd; - Evd.existential_value !evdref ev + Evd.existential_value0 !evdref ev | _ -> Constr.map (check_and_clear_in_constr env evdref err ids global) c @@ -643,7 +643,7 @@ let clear_hyps2_in_evi env evdref hyps t concl ids = let queue_set q is_dependent set = Evar.Set.iter (fun a -> Queue.push (is_dependent,a) q) set let queue_term q is_dependent c = - queue_set q is_dependent (evars_of_term c) + queue_set q is_dependent (evars_of_term (EConstr.Unsafe.to_constr c)) let process_dependent_evar q acc evm is_dependent e = let evi = Evd.find evm e in @@ -656,12 +656,12 @@ let process_dependent_evar q acc evm is_dependent e = match decl with | LocalAssum _ -> () | LocalDef (_,b,_) -> queue_term q true b - end (Environ.named_context_of_val evi.evar_hyps); + end (EConstr.named_context_of_val evi.evar_hyps); match evi.evar_body with | Evar_empty -> if is_dependent then Evar.Map.add e None acc else acc | Evar_defined b -> - let subevars = evars_of_term b in + let subevars = evars_of_term (EConstr.Unsafe.to_constr b) in (* evars appearing in the definition of an evar [e] are marked as dependent when [e] is dependent itself: if [e] is a non-dependent goal, then, unless they are reach from another @@ -729,11 +729,11 @@ let undefined_evars_of_named_context evd nc = ~init:Evar.Set.empty let undefined_evars_of_evar_info evd evi = - Evar.Set.union (undefined_evars_of_term evd (EConstr.of_constr evi.evar_concl)) + Evar.Set.union (undefined_evars_of_term evd evi.evar_concl) (Evar.Set.union (match evi.evar_body with | Evar_empty -> Evar.Set.empty - | Evar_defined b -> undefined_evars_of_term evd (EConstr.of_constr b)) + | Evar_defined b -> undefined_evars_of_term evd b) (undefined_evars_of_named_context evd (named_context_of_val evi.evar_hyps))) @@ -781,10 +781,11 @@ let filtered_undefined_evars_of_evar_info ?cache sigma evi = in let accu = match evi.evar_body with | Evar_empty -> Evar.Set.empty - | Evar_defined b -> evars_of_term b + | Evar_defined b -> evars_of_term (EConstr.Unsafe.to_constr b) in - let accu = Evar.Set.union (undefined_evars_of_term sigma (EConstr.of_constr evi.evar_concl)) accu in - evars_of_named_context cache accu (evar_filtered_context evi) + let accu = Evar.Set.union (undefined_evars_of_term sigma evi.evar_concl) accu in + let ctxt = EConstr.Unsafe.to_named_context (evar_filtered_context evi) in + evars_of_named_context cache accu ctxt (* spiwack: this is a more complete version of {!Termops.occur_evar}. The latter does not look recursively into an @@ -794,7 +795,7 @@ let occur_evar_upto sigma n c = let c = EConstr.Unsafe.to_constr c in let rec occur_rec c = match kind c with | Evar (sp,_) when Evar.equal sp n -> raise Occur - | Evar e -> Option.iter occur_rec (existential_opt_value sigma e) + | Evar e -> Option.iter occur_rec (existential_opt_value0 sigma e) | _ -> Constr.iter occur_rec c in try occur_rec c; false with Occur -> true @@ -849,6 +850,8 @@ let compare_constructor_instances evd u u' = let eq_constr_univs_test sigma1 sigma2 t u = (* spiwack: mild code duplication with {!Evd.eq_constr_univs}. *) let open Evd in + let t = EConstr.Unsafe.to_constr t + and u = EConstr.Unsafe.to_constr u in let fold cstr sigma = try Some (add_universe_constraints sigma cstr) with Univ.UniverseInconsistency _ | UniversesDiffer -> None diff --git a/engine/evarutil.mli b/engine/evarutil.mli index 972b0b9e1..40c1ee082 100644 --- a/engine/evarutil.mli +++ b/engine/evarutil.mli @@ -201,7 +201,7 @@ val kind_of_term_upto : evar_map -> Constr.constr -> universes. The term [t] is interpreted in [sigma1] while [u] is interpreted in [sigma2]. The universe constraints in [sigma2] are assumed to be an extention of those in [sigma1]. *) -val eq_constr_univs_test : evar_map -> evar_map -> Constr.constr -> Constr.constr -> bool +val eq_constr_univs_test : evar_map -> evar_map -> constr -> constr -> bool (** [compare_cumulative_instances cv_pb variance u1 u2 sigma] Returns [Inl sigma'] where [sigma'] is [sigma] augmented with universe diff --git a/engine/evd.ml b/engine/evd.ml index f6e13e1f4..6dcec2760 100644 --- a/engine/evd.ml +++ b/engine/evd.ml @@ -21,6 +21,9 @@ open Environ (* module RelDecl = Context.Rel.Declaration *) module NamedDecl = Context.Named.Declaration +type econstr = constr +type etypes = types + (** Generic filters *) module Filter : sig @@ -537,10 +540,14 @@ let existential_value d (n, args) = | Evar_empty -> raise NotInstantiatedEvar +let existential_value0 = existential_value + let existential_opt_value d ev = try Some (existential_value d ev) with NotInstantiatedEvar -> None +let existential_opt_value0 = existential_opt_value + let existential_type d (n, args) = let info = try find d n @@ -548,6 +555,8 @@ let existential_type d (n, args) = anomaly (str "Evar " ++ str (string_of_existential n) ++ str " was not declared.") in instantiate_evar_array info info.evar_concl args +let existential_type0 = existential_type + let add_constraints d c = { d with universes = UState.add_constraints d.universes c } @@ -1065,6 +1074,7 @@ let meta_ftype evd mv = | Clval(_,_,b) -> b let meta_type evd mv = (meta_ftype evd mv).rebus +let meta_type0 = meta_type let meta_declare mv v ?(name=Anonymous) evd = let metas = Metamap.add mv (Cltyp(name,mk_freelisted v)) evd.metas in @@ -1217,3 +1227,98 @@ let normalize_evar_universe_context_variables = UState.normalize_variables let abstract_undefined_variables = UState.abstract_undefined_variables let normalize_evar_universe_context = UState.minimize let nf_constraints = minimize_universes + +module MiniEConstr = struct + + module ESorts = + struct + type t = Sorts.t + let make s = s + let kind sigma = function + | Sorts.Type u -> Sorts.sort_of_univ (normalize_universe sigma u) + | s -> s + let unsafe_to_sorts s = s + end + + module EInstance = + struct + type t = Univ.Instance.t + let make i = i + let kind sigma i = + if Univ.Instance.is_empty i then i + else normalize_universe_instance sigma i + let empty = Univ.Instance.empty + let is_empty = Univ.Instance.is_empty + let unsafe_to_instance t = t + end + + type t = econstr + + let safe_evar_value sigma ev = + try Some (existential_value sigma ev) + with NotInstantiatedEvar | Not_found -> None + + let rec whd_evar sigma c = + match Constr.kind c with + | Evar ev -> + begin match safe_evar_value sigma ev with + | Some c -> whd_evar sigma c + | None -> c + end + | App (f, args) when isEvar f -> + (** Enforce smart constructor invariant on applications *) + let ev = destEvar f in + begin match safe_evar_value sigma ev with + | None -> c + | Some f -> whd_evar sigma (mkApp (f, args)) + end + | Cast (c0, k, t) when isEvar c0 -> + (** Enforce smart constructor invariant on casts. *) + let ev = destEvar c0 in + begin match safe_evar_value sigma ev with + | None -> c + | Some c -> whd_evar sigma (mkCast (c, k, t)) + end + | _ -> c + + let kind sigma c = Constr.kind (whd_evar sigma c) + let kind_upto = kind + let kind_of_type sigma c = Term.kind_of_type (whd_evar sigma c) + let of_kind = Constr.of_kind + let of_constr c = c + let unsafe_to_constr c = c + let unsafe_eq = Refl + + let to_constr ?(abort_on_undefined_evars=true) sigma c = + let rec to_constr c = match Constr.kind c with + | Evar ev -> + begin match safe_evar_value sigma ev with + | Some c -> to_constr c + | None -> + if abort_on_undefined_evars then + anomaly ~label:"econstr" Pp.(str "grounding a non evar-free term") + else + Constr.map (fun c -> to_constr c) c + end + | Sort (Sorts.Type u) -> + let u' = normalize_universe sigma u in + if u' == u then c else mkSort (Sorts.sort_of_univ u') + | Const (c', u) when not (Univ.Instance.is_empty u) -> + let u' = normalize_universe_instance sigma u in + if u' == u then c else mkConstU (c', u') + | Ind (i, u) when not (Univ.Instance.is_empty u) -> + let u' = normalize_universe_instance sigma u in + if u' == u then c else mkIndU (i, u') + | Construct (co, u) when not (Univ.Instance.is_empty u) -> + let u' = normalize_universe_instance sigma u in + if u' == u then c else mkConstructU (co, u') + | _ -> Constr.map (fun c -> to_constr c) c + in to_constr c + + let of_named_decl d = d + let unsafe_to_named_decl d = d + let of_rel_decl d = d + let unsafe_to_rel_decl d = d + let to_rel_decl sigma d = Context.Rel.Declaration.map_constr (to_constr sigma) d + +end diff --git a/engine/evd.mli b/engine/evd.mli index 911799c44..5ce16459c 100644 --- a/engine/evd.mli +++ b/engine/evd.mli @@ -28,6 +28,9 @@ open Environ It also contains conversion constraints, debugging information and information about meta variables. *) +type econstr +type etypes = econstr + (** {5 Existential variables and unification states} *) type evar = Evar.t @@ -86,16 +89,16 @@ end type evar_body = | Evar_empty - | Evar_defined of constr + | Evar_defined of econstr module Store : Store.S (** Datatype used to store additional information in evar maps. *) type evar_info = { - evar_concl : constr; + evar_concl : econstr; (** Type of the evar. *) - evar_hyps : named_context_val; + evar_hyps : named_context_val; (** TODO econstr? *) (** Context of the evar. *) evar_body : evar_body; (** Optional content of the evar. *) @@ -105,16 +108,16 @@ type evar_info = { in the solution *) evar_source : Evar_kinds.t located; (** Information about the evar. *) - evar_candidates : constr list option; + evar_candidates : econstr list option; (** List of possible solutions when known that it is a finite list *) evar_extra : Store.t (** Extra store, used for clever hacks. *) } -val make_evar : named_context_val -> types -> evar_info -val evar_concl : evar_info -> constr -val evar_context : evar_info -> Context.Named.t -val evar_filtered_context : evar_info -> Context.Named.t +val make_evar : named_context_val -> etypes -> evar_info +val evar_concl : evar_info -> econstr +val evar_context : evar_info -> (econstr, etypes) Context.Named.pt +val evar_filtered_context : evar_info -> (econstr, etypes) Context.Named.pt val evar_hyps : evar_info -> named_context_val val evar_filtered_hyps : evar_info -> named_context_val val evar_body : evar_info -> evar_body @@ -122,8 +125,8 @@ val evar_filter : evar_info -> Filter.t val evar_env : evar_info -> env val evar_filtered_env : evar_info -> env -val map_evar_body : (constr -> constr) -> evar_body -> evar_body -val map_evar_info : (constr -> constr) -> evar_info -> evar_info +val map_evar_body : (econstr -> econstr) -> evar_body -> evar_body +val map_evar_info : (econstr -> econstr) -> evar_info -> evar_info (** {6 Unification state} **) @@ -190,7 +193,7 @@ val raw_map_undefined : (Evar.t -> evar_info -> evar_info) -> evar_map -> evar_m (** Same as {!raw_map}, but restricted to undefined evars. For efficiency reasons. *) -val define : Evar.t-> constr -> evar_map -> evar_map +val define : Evar.t-> econstr -> evar_map -> evar_map (** Set the body of an evar to the given constr. It is expected that: {ul {- The evar is already present in the evarmap.} @@ -198,7 +201,7 @@ val define : Evar.t-> constr -> evar_map -> evar_map {- All the evars present in the constr should be present in the evar map.} } *) -val cmap : (constr -> constr) -> evar_map -> evar_map +val cmap : (econstr -> econstr) -> evar_map -> evar_map (** Map the function on all terms in the evar map. *) val is_evar : evar_map -> Evar.t-> bool @@ -222,20 +225,26 @@ val drop_all_defined : evar_map -> evar_map exception NotInstantiatedEvar -val existential_value : evar_map -> existential -> constr +val existential_value : evar_map -> econstr pexistential -> econstr (** [existential_value sigma ev] raises [NotInstantiatedEvar] if [ev] has no body and [Not_found] if it does not exist in [sigma] *) -val existential_type : evar_map -> existential -> types +val existential_value0 : evar_map -> existential -> constr + +val existential_type : evar_map -> econstr pexistential -> etypes -val existential_opt_value : evar_map -> existential -> constr option +val existential_type0 : evar_map -> existential -> types + +val existential_opt_value : evar_map -> econstr pexistential -> econstr option (** Same as {!existential_value} but returns an option instead of raising an exception. *) +val existential_opt_value0 : evar_map -> existential -> constr option + val evar_instance_array : (Context.Named.Declaration.t -> 'a -> bool) -> evar_info -> 'a array -> (Id.t * 'a) list -val instantiate_evar_array : evar_info -> constr -> constr array -> constr +val instantiate_evar_array : evar_info -> econstr -> econstr array -> econstr val evars_reset_evd : ?with_conv_pbs:bool -> ?with_univs:bool -> evar_map -> evar_map -> evar_map @@ -243,7 +252,7 @@ val evars_reset_evd : ?with_conv_pbs:bool -> ?with_univs:bool -> (** {6 Misc} *) -val restrict : Evar.t-> Filter.t -> ?candidates:constr list -> +val restrict : Evar.t-> Filter.t -> ?candidates:econstr list -> ?src:Evar_kinds.t located -> evar_map -> evar_map * Evar.t (** Restrict an undefined evar into a new evar by filtering context and possibly limiting the instances to a set of candidates *) @@ -251,7 +260,7 @@ val restrict : Evar.t-> Filter.t -> ?candidates:constr list -> val is_restricted_evar : evar_info -> Evar.t option (** Tell if an evar comes from restriction of another evar, and if yes, which *) -val downcast : Evar.t-> types -> evar_map -> evar_map +val downcast : Evar.t-> etypes -> evar_map -> evar_map (** Change the type of an undefined evar to a new type assumed to be a subtype of its current type; subtyping must be ensured by caller *) @@ -341,7 +350,7 @@ val shelve_on_future_goals : Evar.t list -> future_goals -> future_goals Evar maps also keep track of the universe constraints defined at a given point. This section defines the relevant manipulation functions. *) -val whd_sort_variable : evar_map -> constr -> constr +val whd_sort_variable : evar_map -> econstr -> econstr exception UniversesDiffer @@ -397,8 +406,8 @@ type 'a freelisted = { rebus : 'a; freemetas : Metaset.t } -val metavars_of : constr -> Metaset.t -val mk_freelisted : constr -> constr freelisted +val metavars_of : econstr -> Metaset.t +val mk_freelisted : econstr -> econstr freelisted val map_fl : ('a -> 'b) -> 'a freelisted -> 'b freelisted (** Status of an instance found by unification wrt to the meta it solves: @@ -436,12 +445,12 @@ type instance_status = instance_constraint * instance_typing_status (** Clausal environments *) type clbinding = - | Cltyp of Name.t * constr freelisted - | Clval of Name.t * (constr freelisted * instance_status) * constr freelisted + | Cltyp of Name.t * econstr freelisted + | Clval of Name.t * (econstr freelisted * instance_status) * econstr freelisted (** Unification constraints *) type conv_pb = Reduction.conv_pb -type evar_constraint = conv_pb * env * constr * constr +type evar_constraint = conv_pb * env * econstr * econstr val add_conv_pb : ?tail:bool -> evar_constraint -> evar_map -> evar_map val extract_changed_conv_pbs : evar_map -> @@ -457,7 +466,7 @@ val loc_of_conv_pb : evar_map -> evar_constraint -> Loc.t option val evars_of_term : constr -> Evar.Set.t (** including evars in instances of evars *) -val evars_of_named_context : Context.Named.t -> Evar.Set.t +val evars_of_named_context : (econstr, etypes) Context.Named.pt -> Evar.Set.t val evars_of_filtered_evar_info : evar_info -> Evar.Set.t @@ -465,19 +474,20 @@ val evars_of_filtered_evar_info : evar_info -> Evar.Set.t val meta_list : evar_map -> (metavariable * clbinding) list val meta_defined : evar_map -> metavariable -> bool -val meta_value : evar_map -> metavariable -> constr +val meta_value : evar_map -> metavariable -> econstr (** [meta_fvalue] raises [Not_found] if meta not in map or [Anomaly] if meta has no value *) -val meta_fvalue : evar_map -> metavariable -> constr freelisted * instance_status -val meta_opt_fvalue : evar_map -> metavariable -> (constr freelisted * instance_status) option -val meta_type : evar_map -> metavariable -> types -val meta_ftype : evar_map -> metavariable -> types freelisted +val meta_fvalue : evar_map -> metavariable -> econstr freelisted * instance_status +val meta_opt_fvalue : evar_map -> metavariable -> (econstr freelisted * instance_status) option +val meta_type : evar_map -> metavariable -> etypes +val meta_type0 : evar_map -> metavariable -> types +val meta_ftype : evar_map -> metavariable -> etypes freelisted val meta_name : evar_map -> metavariable -> Name.t val meta_declare : - metavariable -> types -> ?name:Name.t -> evar_map -> evar_map -val meta_assign : metavariable -> constr * instance_status -> evar_map -> evar_map -val meta_reassign : metavariable -> constr * instance_status -> evar_map -> evar_map + metavariable -> etypes -> ?name:Name.t -> evar_map -> evar_map +val meta_assign : metavariable -> econstr * instance_status -> evar_map -> evar_map +val meta_reassign : metavariable -> econstr * instance_status -> evar_map -> evar_map val clear_metas : evar_map -> evar_map @@ -485,10 +495,10 @@ val clear_metas : evar_map -> evar_map val meta_merge : ?with_univs:bool -> evar_map -> evar_map -> evar_map val undefined_metas : evar_map -> metavariable list -val map_metas_fvalue : (constr -> constr) -> evar_map -> evar_map -val map_metas : (constr -> constr) -> evar_map -> evar_map +val map_metas_fvalue : (econstr -> econstr) -> evar_map -> evar_map +val map_metas : (econstr -> econstr) -> evar_map -> evar_map -type metabinding = metavariable * constr * instance_status +type metabinding = metavariable * econstr * instance_status val retract_coercible_metas : evar_map -> metabinding list * evar_map @@ -639,13 +649,13 @@ val fresh_inductive_instance : ?loc:Loc.t -> env -> evar_map -> inductive -> eva val fresh_constructor_instance : ?loc:Loc.t -> env -> evar_map -> constructor -> evar_map * pconstructor val fresh_global : ?loc:Loc.t -> ?rigid:rigid -> ?names:Univ.Instance.t -> env -> - evar_map -> Globnames.global_reference -> evar_map * constr + evar_map -> Globnames.global_reference -> evar_map * econstr (********************************************************************) (* constr with holes and pending resolution of classes, conversion *) (* problems, candidates, etc. *) -type open_constr = evar_map * constr (* Special case when before is empty *) +type open_constr = evar_map * econstr (* Special case when before is empty *) (** Partially constructed constrs. *) @@ -665,3 +675,50 @@ val create_evar_defs : evar_map -> evar_map (** Create an [evar_map] with empty meta map: *) +(** Use this module only to bootstrap EConstr *) +module MiniEConstr : sig + module ESorts : sig + type t + val make : Sorts.t -> t + val kind : evar_map -> t -> Sorts.t + val unsafe_to_sorts : t -> Sorts.t + end + + module EInstance : sig + type t + val make : Univ.Instance.t -> t + val kind : evar_map -> t -> Univ.Instance.t + val empty : t + val is_empty : t -> bool + val unsafe_to_instance : t -> Univ.Instance.t + end + + type t = econstr + + val kind : evar_map -> t -> (t, t, ESorts.t, EInstance.t) Constr.kind_of_term + val kind_upto : evar_map -> constr -> (constr, types, Sorts.t, Univ.Instance.t) Constr.kind_of_term + val kind_of_type : evar_map -> t -> (t, t) Term.kind_of_type + + val whd_evar : evar_map -> t -> t + + val of_kind : (t, t, ESorts.t, EInstance.t) Constr.kind_of_term -> t + + val of_constr : Constr.t -> t + + val to_constr : ?abort_on_undefined_evars:bool -> evar_map -> t -> Constr.t + + val unsafe_to_constr : t -> Constr.t + + val unsafe_eq : (t, Constr.t) eq + + val of_named_decl : (Constr.t, Constr.types) Context.Named.Declaration.pt -> + (t, t) Context.Named.Declaration.pt + val unsafe_to_named_decl : (t, t) Context.Named.Declaration.pt -> + (Constr.t, Constr.types) Context.Named.Declaration.pt + val unsafe_to_rel_decl : (t, t) Context.Rel.Declaration.pt -> + (Constr.t, Constr.types) Context.Rel.Declaration.pt + val of_rel_decl : (Constr.t, Constr.types) Context.Rel.Declaration.pt -> + (t, t) Context.Rel.Declaration.pt + val to_rel_decl : evar_map -> (t, t) Context.Rel.Declaration.pt -> + (Constr.t, Constr.types) Context.Rel.Declaration.pt +end diff --git a/engine/proofview.ml b/engine/proofview.ml index 639f48e77..54237ceb4 100644 --- a/engine/proofview.ml +++ b/engine/proofview.ml @@ -45,9 +45,9 @@ let compact el ({ solution } as pv) = let pruned_solution = Evd.drop_all_defined solution in let apply_subst_einfo _ ei = Evd.({ ei with - evar_concl = nf0 ei.evar_concl; + evar_concl = nf ei.evar_concl; evar_hyps = Environ.map_named_val nf0 ei.evar_hyps; - evar_candidates = Option.map (List.map nf0) ei.evar_candidates }) in + evar_candidates = Option.map (List.map nf) ei.evar_candidates }) in let new_solution = Evd.raw_map_undefined apply_subst_einfo pruned_solution in let new_size = Evd.fold (fun _ _ i -> i+1) new_solution 0 in Feedback.msg_info (Pp.str (Printf.sprintf "Evars: %d -> %d\n" size new_size)); @@ -875,8 +875,7 @@ module Progress = struct (** equality function on hypothesis contexts *) let eq_named_context_val sigma1 sigma2 ctx1 ctx2 = - let open Environ in - let c1 = named_context_of_val ctx1 and c2 = named_context_of_val ctx2 in + let c1 = EConstr.named_context_of_val ctx1 and c2 = EConstr.named_context_of_val ctx2 in let eq_named_declaration d1 d2 = match d1, d2 with | LocalAssum (i1,t1), LocalAssum (i2,t2) -> @@ -1101,7 +1100,7 @@ module Goal = struct let gmake_with info env sigma goal state = { env = Environ.reset_with_named_context (Evd.evar_filtered_hyps info) env ; sigma = sigma ; - concl = EConstr.of_constr (Evd.evar_concl info); + concl = Evd.evar_concl info; state = state ; self = goal } diff --git a/engine/termops.ml b/engine/termops.ml index b7531f6fc..df43be28e 100644 --- a/engine/termops.ml +++ b/engine/termops.ml @@ -115,7 +115,7 @@ let pr_evar_suggested_name evk sigma = | _,Evar_kinds.GoalEvar -> Id.of_string "Goal" | _ -> let env = reset_with_named_context evi.evar_hyps (Global.env()) in - Namegen.id_of_name_using_hdchar env sigma (EConstr.of_constr evi.evar_concl) Anonymous + Namegen.id_of_name_using_hdchar env sigma evi.evar_concl Anonymous in let names = EvMap.mapi base_id (undefined_map sigma) in let id = EvMap.find evk names in @@ -154,7 +154,7 @@ let protect f x = with e -> str "EXCEPTION: " ++ str (Printexc.to_string e) let print_kconstr a = - protect (fun c -> print_constr (EConstr.of_constr c)) a + protect (fun c -> print_constr c) a let pr_meta_map evd = let open Evd in @@ -197,11 +197,11 @@ let pr_evar_source = function let print_constr = print_kconstr in let id = Option.get ido in str "parameter " ++ Id.print id ++ spc () ++ str "of" ++ - spc () ++ print_constr (printable_constr_of_global c) + spc () ++ print_constr (EConstr.of_constr @@ printable_constr_of_global c) | Evar_kinds.InternalHole -> str "internal placeholder" | Evar_kinds.TomatchTypeParameter (ind,n) -> let print_constr = print_kconstr in - pr_nth n ++ str " argument of type " ++ print_constr (mkInd ind) + pr_nth n ++ str " argument of type " ++ print_constr (EConstr.mkInd ind) | Evar_kinds.GoalEvar -> str "goal evar" | Evar_kinds.ImpossibleCase -> str "type of impossible pattern-matching clause" | Evar_kinds.MatchingVar _ -> str "matching variable" @@ -256,7 +256,7 @@ let compute_evar_dependency_graph sigma = in match evar_body evi with | Evar_empty -> acc - | Evar_defined c -> Evar.Set.fold fold_ev (evars_of_term c) acc + | Evar_defined c -> Evar.Set.fold fold_ev (evars_of_term (EConstr.Unsafe.to_constr c)) acc in Evd.fold fold sigma EvMap.empty @@ -314,7 +314,8 @@ let print_env_short env = let print_constr = print_kconstr in let pr_rel_decl = function | RelDecl.LocalAssum (n,_) -> Name.print n - | RelDecl.LocalDef (n,b,_) -> str "(" ++ Name.print n ++ str " := " ++ print_constr b ++ str ")" + | RelDecl.LocalDef (n,b,_) -> str "(" ++ Name.print n ++ str " := " + ++ print_constr (EConstr.of_constr b) ++ str ")" in let pr_named_decl = NamedDecl.to_rel_decl %> pr_rel_decl in let nc = List.rev (named_context env) in @@ -335,11 +336,11 @@ let pr_evar_constraints sigma pbs = Namegen.make_all_name_different env sigma in print_env_short env ++ spc () ++ str "|-" ++ spc () ++ - protect (print_constr_env env sigma) (EConstr.of_constr t1) ++ spc () ++ + protect (print_constr_env env sigma) t1 ++ spc () ++ str (match pbty with | Reduction.CONV -> "==" | Reduction.CUMUL -> "<=") ++ - spc () ++ protect (print_constr_env env Evd.empty) (EConstr.of_constr t2) + spc () ++ protect (print_constr_env env Evd.empty) t2 in prlist_with_sep fnl pr_evconstr pbs diff --git a/plugins/cc/cctac.ml b/plugins/cc/cctac.ml index d19817e74..c4db49cd3 100644 --- a/plugins/cc/cctac.ml +++ b/plugins/cc/cctac.ml @@ -90,7 +90,7 @@ let rec decompose_term env sigma t= decompose_term env sigma c | _ -> let t = Termops.strip_outer_cast sigma t in - if closed0 sigma t then Symb (EConstr.to_constr sigma t) else raise Not_found + if closed0 sigma t then Symb (EConstr.to_constr ~abort_on_undefined_evars:false sigma t) else raise Not_found (* decompose equality in members and type *) open Termops diff --git a/plugins/firstorder/sequent.ml b/plugins/firstorder/sequent.ml index 285991797..7c612c0d8 100644 --- a/plugins/firstorder/sequent.ml +++ b/plugins/firstorder/sequent.ml @@ -77,14 +77,14 @@ module CM=Map.Make(Constr) module History=Set.Make(Hitem) let cm_add sigma typ nam cm= - let typ = EConstr.to_constr sigma typ in + let typ = EConstr.to_constr ~abort_on_undefined_evars:false sigma typ in try let l=CM.find typ cm in CM.add typ (nam::l) cm with Not_found->CM.add typ [nam] cm let cm_remove sigma typ nam cm= - let typ = EConstr.to_constr sigma typ in + let typ = EConstr.to_constr ~abort_on_undefined_evars:false sigma typ in try let l=CM.find typ cm in let l0=List.filter (fun id-> not (Globnames.eq_gr id nam)) l in @@ -152,7 +152,7 @@ let re_add_formula_list sigma lf seq= redexes=List.fold_right HP.add lf seq.redexes; context=List.fold_right do_one lf seq.context} -let find_left sigma t seq=List.hd (CM.find (EConstr.to_constr sigma t) seq.context) +let find_left sigma t seq=List.hd (CM.find (EConstr.to_constr ~abort_on_undefined_evars:false sigma t) seq.context) (*let rev_left seq= try @@ -197,7 +197,7 @@ let extend_with_ref_list env sigma l seq = let l = expand_constructor_hints l in let f gr (seq, sigma) = let sigma, c = Evd.fresh_global env sigma gr in - let sigma, typ= Typing.type_of env sigma (EConstr.of_constr c) in + let sigma, typ= Typing.type_of env sigma c in (add_formula env sigma Hyp gr typ seq, sigma) in List.fold_right f l (seq, sigma) diff --git a/plugins/funind/functional_principles_proofs.ml b/plugins/funind/functional_principles_proofs.ml index d04887a48..8da0e1c4f 100644 --- a/plugins/funind/functional_principles_proofs.ml +++ b/plugins/funind/functional_principles_proofs.ml @@ -1050,8 +1050,7 @@ let do_replace (evd:Evd.evar_map ref) params rec_arg_num rev_args_id f fun_num a (Global.env ()) !evd (Constrintern.locate_reference (qualid_of_ident equation_lemma_id)) in - let res = EConstr.of_constr res in - evd:=evd'; + evd:=evd'; let _ = Typing.e_type_of ~refresh:true (Global.env ()) evd res in res in diff --git a/plugins/funind/functional_principles_types.ml b/plugins/funind/functional_principles_types.ml index 804548ce5..04a23cdb9 100644 --- a/plugins/funind/functional_principles_types.ml +++ b/plugins/funind/functional_principles_types.ml @@ -266,7 +266,7 @@ let change_property_sort evd toSort princ princName = (Global.env ()) evd (Constrintern.locate_reference (Libnames.qualid_of_ident princName)) in let init = let nargs = (princ_info.nparams + (List.length princ_info.predicates)) in - mkApp(princName_as_constr, + mkApp(EConstr.Unsafe.to_constr princName_as_constr, Array.init nargs (fun i -> mkRel (nargs - i ))) in @@ -630,11 +630,14 @@ let build_scheme fas = in let evd',f = Evd.fresh_global (Global.env ()) !evd f_as_constant in let _ = evd := evd' in - let _ = Typing.e_type_of ~refresh:true (Global.env ()) evd (EConstr.of_constr f) in - if isConst f - then (destConst f,sort) - else user_err Pp.(pr_constr_env (Global.env ()) !evd f ++spc () ++ str "should be the named of a globally defined function") - ) + let _ = Typing.e_type_of ~refresh:true (Global.env ()) evd f in + let c, u = + try EConstr.destConst !evd f + with DestKO -> + user_err Pp.(pr_econstr_env (Global.env ()) !evd f ++spc () ++ str "should be the named of a globally defined function") + in + (c, EConstr.EInstance.kind !evd u), sort + ) fas ) in let bodies_types = diff --git a/plugins/funind/glob_termops.ml b/plugins/funind/glob_termops.ml index 40ea40b6b..845104c3c 100644 --- a/plugins/funind/glob_termops.ml +++ b/plugins/funind/glob_termops.ml @@ -564,6 +564,7 @@ let resolve_and_replace_implicits ?(flags=Pretyping.all_and_fail_flags) ?(expect If someone knows how to prevent solved existantial removal in understand, please do not hesitate to change the computation of [ctx] here *) let ctx,_,_ = Pretyping.ise_pretype_gen flags env sigma Glob_ops.empty_lvar expected_type rt in let ctx, f = Evarutil.nf_evars_and_universes ctx in + let f c = EConstr.of_constr (f (EConstr.Unsafe.to_constr c)) in (* then we map [rt] to replace the implicit holes by their values *) let rec change rt = @@ -586,8 +587,8 @@ If someone knows how to prevent solved existantial removal in understand, pleas with Found evi -> (* we found the evar corresponding to this hole *) match evi.evar_body with | Evar_defined c -> - (* we just have to lift the solution in glob_term *) - Detyping.detype Detyping.Now false Id.Set.empty env ctx (EConstr.of_constr (f c)) + (* we just have to lift the solution in glob_term *) + Detyping.detype Detyping.Now false Id.Set.empty env ctx (f c) | Evar_empty -> rt (* the hole was not solved : we do nothing *) ) | (GHole(BinderType na,_,_)) -> (* we only want to deal with implicit arguments *) @@ -609,7 +610,7 @@ If someone knows how to prevent solved existantial removal in understand, pleas match evi.evar_body with | Evar_defined c -> (* we just have to lift the solution in glob_term *) - Detyping.detype Detyping.Now false Id.Set.empty env ctx (EConstr.of_constr (f c)) + Detyping.detype Detyping.Now false Id.Set.empty env ctx (f c) | Evar_empty -> rt (* the hole was not solved : we d when falseo nothing *) in res diff --git a/plugins/funind/indfun.ml b/plugins/funind/indfun.ml index d395e3601..748d8add2 100644 --- a/plugins/funind/indfun.ml +++ b/plugins/funind/indfun.ml @@ -77,8 +77,7 @@ let functional_induction with_clean c princl pat = user_err (str "Cannot find induction principle for " ++ Printer.pr_leconstr_env (Tacmach.pf_env g) sigma (mkConst c') ) in - let princ = EConstr.of_constr princ in - (princ,NoBindings,Tacmach.pf_unsafe_type_of g' princ,g') + (princ,NoBindings,Tacmach.pf_unsafe_type_of g' princ,g') | _ -> raise (UserError(None,str "functional induction must be used with a function" )) end | Some ((princ,binding)) -> @@ -261,7 +260,6 @@ let derive_inversion fix_names = let evd,c = Evd.fresh_global (Global.env ()) evd (Constrintern.locate_reference (Libnames.qualid_of_ident id)) in - let c = EConstr.of_constr c in let (cst, u) = destConst evd c in evd, (cst, EInstance.kind evd u) :: l ) @@ -283,8 +281,7 @@ let derive_inversion fix_names = (Global.env ()) evd (Constrintern.locate_reference (Libnames.qualid_of_ident (mk_rel_id id))) in - let id = EConstr.of_constr id in - evd,(fst (destInd evd id))::l + evd,(fst (destInd evd id))::l ) fix_names (evd',[]) @@ -388,7 +385,7 @@ let generate_principle (evd:Evd.evar_map ref) pconstants on_error let evd = ref (Evd.from_env env) in let evd',uprinc = Evd.fresh_global env !evd princ in let _ = evd := evd' in - let princ_type = Typing.e_type_of ~refresh:true env evd (EConstr.of_constr uprinc) in + let princ_type = Typing.e_type_of ~refresh:true env evd uprinc in let princ_type = EConstr.Unsafe.to_constr princ_type in Functional_principles_types.generate_functional_principle evd @@ -425,7 +422,6 @@ let register_struct is_rec (fixpoint_exprl:(Vernacexpr.fixpoint_expr * Vernacexp let evd,c = Evd.fresh_global (Global.env ()) evd (Constrintern.locate_reference (Libnames.qualid_of_ident fname)) in - let c = EConstr.of_constr c in let (cst, u) = destConst evd c in let u = EInstance.kind evd u in evd,((cst, u) :: l) @@ -442,7 +438,6 @@ let register_struct is_rec (fixpoint_exprl:(Vernacexpr.fixpoint_expr * Vernacexp let evd,c = Evd.fresh_global (Global.env ()) evd (Constrintern.locate_reference (Libnames.qualid_of_ident fname)) in - let c = EConstr.of_constr c in let (cst, u) = destConst evd c in let u = EInstance.kind evd u in evd,((cst, u) :: l) diff --git a/plugins/funind/invfun.ml b/plugins/funind/invfun.ml index ae84eaa93..28e85268a 100644 --- a/plugins/funind/invfun.ml +++ b/plugins/funind/invfun.ml @@ -102,7 +102,6 @@ let generate_type evd g_to_f f graph i = let evd',graph = Evd.fresh_global (Global.env ()) !evd (Globnames.IndRef (fst (destInd !evd graph))) in - let graph = EConstr.of_constr graph in evd:=evd'; let graph_arity = Typing.e_type_of (Global.env ()) evd graph in let ctxt,_ = decompose_prod_assum !evd graph_arity in @@ -172,7 +171,6 @@ let find_induction_principle evd f = | None -> raise Not_found | Some rect_lemma -> let evd',rect_lemma = Evd.fresh_global (Global.env ()) !evd (Globnames.ConstRef rect_lemma) in - let rect_lemma = EConstr.of_constr rect_lemma in let evd',typ = Typing.type_of ~refresh:true (Global.env ()) evd' rect_lemma in evd:=evd'; rect_lemma,typ @@ -823,8 +821,7 @@ let derive_correctness make_scheme (funs: pconstant list) (graphs:inductive list (* let lem_cst = fst (destConst (Constrintern.global_reference lem_id)) in *) let _,lem_cst_constr = Evd.fresh_global (Global.env ()) !evd (Constrintern.locate_reference (Libnames.qualid_of_ident lem_id)) in - let lem_cst_constr = EConstr.of_constr lem_cst_constr in - let (lem_cst,_) = destConst !evd lem_cst_constr in + let (lem_cst,_) = destConst !evd lem_cst_constr in update_Function {finfo with correctness_lemma = Some lem_cst}; ) @@ -884,8 +881,7 @@ let derive_correctness make_scheme (funs: pconstant list) (graphs:inductive list let finfo = find_Function_infos (fst f_as_constant) in let _,lem_cst_constr = Evd.fresh_global (Global.env ()) !evd (Constrintern.locate_reference (Libnames.qualid_of_ident lem_id)) in - let lem_cst_constr = EConstr.of_constr lem_cst_constr in - let (lem_cst,_) = destConst !evd lem_cst_constr in + let (lem_cst,_) = destConst !evd lem_cst_constr in update_Function {finfo with completeness_lemma = Some lem_cst} ) funs) diff --git a/plugins/ltac/extratactics.ml4 b/plugins/ltac/extratactics.ml4 index 2e90ce90c..a5f8060ae 100644 --- a/plugins/ltac/extratactics.ml4 +++ b/plugins/ltac/extratactics.ml4 @@ -296,7 +296,6 @@ let project_hint ~poly pri l2r r = let env = Global.env() in let sigma = Evd.from_env env in let sigma, c = Evd.fresh_global env sigma gr in - let c = EConstr.of_constr c in let t = Retyping.get_type_of env sigma c in let t = Tacred.reduce_to_quantified_ref env sigma (Lazy.force coq_iff_ref) t in @@ -307,7 +306,6 @@ let project_hint ~poly pri l2r r = let p = if l2r then build_coq_iff_left_proj () else build_coq_iff_right_proj () in let sigma, p = Evd.fresh_global env sigma p in - let p = EConstr.of_constr p in let c = Reductionops.whd_beta sigma (mkApp (c, Context.Rel.to_extended_vect mkRel 0 sign)) in let c = it_mkLambda_or_LetIn (mkApp (p,[|mkArrow a (lift 1 b);mkArrow b (lift 1 a);c|])) sign in diff --git a/plugins/ltac/rewrite.ml b/plugins/ltac/rewrite.ml index d32a2faef..9eb55aa5e 100644 --- a/plugins/ltac/rewrite.ml +++ b/plugins/ltac/rewrite.ml @@ -428,7 +428,8 @@ let split_head = function | [] -> assert(false) let eq_pb (ty, env, x, y as pb) (ty', env', x', y' as pb') = - pb == pb' || (ty == ty' && Constr.equal x x' && Constr.equal y y') + let equal x y = Constr.equal (EConstr.Unsafe.to_constr x) (EConstr.Unsafe.to_constr y) in + pb == pb' || (ty == ty' && equal x x' && equal y y') let problem_inclusion x y = List.for_all (fun pb -> List.exists (fun pb' -> eq_pb pb pb') y) x @@ -626,9 +627,9 @@ let solve_remaining_by env sigma holes by = (** Evar should not be defined, but just in case *) | Some evi -> let env = Environ.reset_with_named_context evi.evar_hyps env in - let ty = EConstr.of_constr evi.evar_concl in + let ty = evi.evar_concl in let c, sigma = Pfedit.refine_by_tactic env sigma ty solve_tac in - Evd.define evk c sigma + Evd.define evk (EConstr.of_constr c) sigma in List.fold_left solve sigma indep @@ -1862,7 +1863,6 @@ let declare_projection n instance_id r = let env = Global.env () in let sigma = Evd.from_env env in let sigma,c = Evd.fresh_global env sigma r in - let c = EConstr.of_constr c in let ty = Retyping.get_type_of env sigma c in let term = proper_projection sigma c ty in let sigma, typ = Typing.type_of env sigma term in diff --git a/plugins/ssr/ssrcommon.ml b/plugins/ssr/ssrcommon.ml index d5118da4c..06c26edbe 100644 --- a/plugins/ssr/ssrcommon.ml +++ b/plugins/ssr/ssrcommon.ml @@ -504,16 +504,17 @@ let nf_evar sigma t = EConstr.Unsafe.to_constr (Evarutil.nf_evar sigma (EConstr.of_constr t)) let pf_abs_evars2 gl rigid (sigma, c0) = - let c0 = EConstr.to_constr sigma c0 in + let c0 = EConstr.to_constr ~abort_on_undefined_evars:false sigma c0 in let sigma0, ucst = project gl, Evd.evar_universe_context sigma in let nenv = env_size (pf_env gl) in let abs_evar n k = let evi = Evd.find sigma k in - let dc = CList.firstn n (evar_filtered_context evi) in + let concl = EConstr.Unsafe.to_constr evi.evar_concl in + let dc = EConstr.Unsafe.to_named_context (CList.firstn n (evar_filtered_context evi)) in let abs_dc c = function | NamedDecl.LocalDef (x,b,t) -> mkNamedLetIn x b t (mkArrow t c) | NamedDecl.LocalAssum (x,t) -> mkNamedProd x t c in - let t = Context.Named.fold_inside abs_dc ~init:evi.evar_concl dc in + let t = Context.Named.fold_inside abs_dc ~init:concl dc in nf_evar sigma t in let rec put evlist c = match Constr.kind c with | Evar (k, a) -> @@ -569,11 +570,12 @@ let pf_abs_evars_pirrel gl (sigma, c0) = let nenv = env_size (pf_env gl) in let abs_evar n k = let evi = Evd.find sigma k in - let dc = CList.firstn n (evar_filtered_context evi) in + let concl = EConstr.Unsafe.to_constr evi.evar_concl in + let dc = EConstr.Unsafe.to_named_context (CList.firstn n (evar_filtered_context evi)) in let abs_dc c = function | NamedDecl.LocalDef (x,b,t) -> mkNamedLetIn x b t (mkArrow t c) | NamedDecl.LocalAssum (x,t) -> mkNamedProd x t c in - let t = Context.Named.fold_inside abs_dc ~init:evi.evar_concl dc in + let t = Context.Named.fold_inside abs_dc ~init:concl dc in nf_evar sigma0 (nf_evar sigma t) in let rec put evlist c = match Constr.kind c with | Evar (k, a) -> @@ -581,7 +583,7 @@ let pf_abs_evars_pirrel gl (sigma, c0) = let n = max 0 (Array.length a - nenv) in let k_ty = Retyping.get_sort_family_of - (pf_env gl) sigma (EConstr.of_constr (Evd.evar_concl (Evd.find sigma k))) in + (pf_env gl) sigma (Evd.evar_concl (Evd.find sigma k)) in let is_prop = k_ty = InProp in let t = abs_evar n k in (k, (n, t, is_prop)) :: put evlist t | _ -> Constr.fold put evlist c in @@ -746,7 +748,7 @@ let pf_mkSsrConst name gl = let pf_fresh_global name gl = let sigma, env, it = project gl, pf_env gl, sig_it gl in let sigma,t = Evd.fresh_global env sigma name in - t, re_sig it sigma + EConstr.Unsafe.to_constr t, re_sig it sigma let mkProt t c gl = let prot, gl = pf_mkSsrConst "protect_term" gl in @@ -980,7 +982,7 @@ let applyn ~with_evars ?beta ?(with_shelve=false) n t gl = if not (EConstr.Vars.closed0 sigma ty) then raise dependent_apply_error; let m = Evarutil.new_meta () in - loop (meta_declare m (EConstr.Unsafe.to_constr ty) sigma) bo ((EConstr.mkMeta m)::args) (n-1) + loop (meta_declare m ty sigma) bo ((EConstr.mkMeta m)::args) (n-1) | _ -> assert false in loop sigma t [] n in pp(lazy(str"Refiner.refiner " ++ Printer.pr_econstr_env (pf_env gl) (project gl) t)); diff --git a/plugins/ssr/ssrelim.ml b/plugins/ssr/ssrelim.ml index 717657a24..de8ffb976 100644 --- a/plugins/ssr/ssrelim.ml +++ b/plugins/ssr/ssrelim.ml @@ -356,7 +356,7 @@ let ssrelim ?(ind=ref None) ?(is_case=false) deps what ?elim eqid elim_intro_tac let ev = List.fold_left Evar.Set.union Evar.Set.empty patterns_ev in let ty_ev = Evar.Set.fold (fun i e -> let ex = i in - let i_ty = EConstr.of_constr (Evd.evar_concl (Evd.find (project gl) ex)) in + let i_ty = Evd.evar_concl (Evd.find (project gl) ex) in Evar.Set.union e (evars_of_term i_ty)) ev Evar.Set.empty in let inter = Evar.Set.inter ev ty_ev in diff --git a/plugins/ssr/ssrequality.ml b/plugins/ssr/ssrequality.ml index 57635edac..7748ba2b0 100644 --- a/plugins/ssr/ssrequality.ml +++ b/plugins/ssr/ssrequality.ml @@ -276,7 +276,7 @@ let unfoldintac occ rdx t (kt,_) gl = let foldtac occ rdx ft gl = let sigma0, concl0, env0 = project gl, pf_concl gl, pf_env gl in let sigma, t = ft in - let t = EConstr.to_constr sigma t in + let t = EConstr.to_constr ~abort_on_undefined_evars:false sigma t in let fold, conclude = match rdx with | Some (_, (In_T _ | In_X_In_T _)) | None -> let ise = Evd.create_evar_defs sigma in @@ -359,7 +359,7 @@ let pirrel_rewrite pred rdx rdx_ty new_rdx dir (sigma, c) c_ty gl = let evs = Evar.Set.elements (Evarutil.undefined_evars_of_term sigma t) in let open_evs = List.filter (fun k -> Sorts.InProp <> Retyping.get_sort_family_of - env sigma (EConstr.of_constr (Evd.evar_concl (Evd.find sigma k)))) + env sigma (Evd.evar_concl (Evd.find sigma k))) evs in if open_evs <> [] then Some name else None) (List.combine (Array.to_list args) names) @@ -478,10 +478,10 @@ let rwprocess_rule dir rule gl = | _ -> let ra = Array.append a [|r|] in function 1 -> let sigma, pi1 = Evd.fresh_global env sigma coq_prod.Coqlib.proj1 in - EConstr.mkApp (EConstr.of_constr pi1, ra), sigma + EConstr.mkApp (pi1, ra), sigma | _ -> let sigma, pi2 = Evd.fresh_global env sigma coq_prod.Coqlib.proj2 in - EConstr.mkApp (EConstr.of_constr pi2, ra), sigma in + EConstr.mkApp (pi2, ra), sigma in if EConstr.eq_constr sigma a.(0) (EConstr.of_constr (Universes.constr_of_global @@ Coqlib.build_coq_True ())) then let s, sigma = sr sigma 2 in loop (converse_dir d) sigma s a.(1) rs 0 @@ -557,7 +557,7 @@ let rwrxtac occ rdx_pat dir rule gl = let rpat env sigma0 (sigma, pats) (d, r, lhs, rhs) = let sigma, pat = let rw_progress rhs t evd = rw_progress rhs (EConstr.of_constr t) evd in - mk_tpattern env sigma0 (sigma,EConstr.to_constr sigma r) (rw_progress rhs) d (EConstr.to_constr sigma lhs) in + mk_tpattern env sigma0 (sigma, EConstr.to_constr ~abort_on_undefined_evars:false sigma r) (rw_progress rhs) d (EConstr.to_constr ~abort_on_undefined_evars:false sigma lhs) in sigma, pats @ [pat] in let rpats = List.fold_left (rpat env0 sigma0) (r_sigma,[]) rules in let find_R, end_R = mk_tpattern_matcher sigma0 occ ~upats_origin rpats in @@ -567,7 +567,7 @@ let rwrxtac occ rdx_pat dir rule gl = let r = ref None in (fun env c _ h -> do_once r (fun () -> find_rule (EConstr.of_constr c), c); mkRel h), (fun concl -> closed0_check concl e gl; - let (d,(ev,ctx,c)) , x = assert_done r in (d,(ev,ctx, EConstr.to_constr ev c)) , x) in + let (d,(ev,ctx,c)) , x = assert_done r in (d,(ev,ctx, EConstr.to_constr ~abort_on_undefined_evars:false ev c)) , x) in let concl0 = EConstr.Unsafe.to_constr concl0 in let concl = eval_pattern env0 sigma0 concl0 rdx_pat occ find_R in let (d, r), rdx = conclude concl in @@ -589,7 +589,10 @@ let ssrinstancesofrule ist dir arg gl = let rpat env sigma0 (sigma, pats) (d, r, lhs, rhs) = let sigma, pat = let rw_progress rhs t evd = rw_progress rhs (EConstr.of_constr t) evd in - mk_tpattern env sigma0 (sigma,EConstr.to_constr sigma r) (rw_progress rhs) d (EConstr.to_constr sigma lhs) in + mk_tpattern env sigma0 + (sigma,EConstr.to_constr ~abort_on_undefined_evars:false sigma r) + (rw_progress rhs) d + (EConstr.to_constr ~abort_on_undefined_evars:false sigma lhs) in sigma, pats @ [pat] in let rpats = List.fold_left (rpat env0 sigma0) (r_sigma,[]) rules in mk_tpattern_matcher ~all_instances:true ~raise_NoMatch:true sigma0 None ~upats_origin rpats in diff --git a/plugins/ssr/ssripats.ml b/plugins/ssr/ssripats.ml index 7897cb170..6b7a96deb 100644 --- a/plugins/ssr/ssripats.ml +++ b/plugins/ssr/ssripats.ml @@ -418,7 +418,7 @@ let tclLAST_GEN ~to_ind ((oclr, occ), t) conclusion = tclINDEPENDENTL begin Goal.enter_one begin fun g -> let pat = Ssrmatching.interp_cpattern sigma0 t None in let cl0, env, sigma, hyps = Goal.(concl g, env g, sigma g, hyps g) in - let cl = EConstr.to_constr sigma cl0 in + let cl = EConstr.to_constr ~abort_on_undefined_evars:false sigma cl0 in let (c, ucst), cl = try Ssrmatching.fill_occ_pattern ~raise_NoMatch:true env sigma cl pat occ 1 with Ssrmatching.NoMatch -> Ssrmatching.redex_of_pattern env pat, cl in @@ -623,7 +623,7 @@ let tacFIND_ABSTRACT_PROOF check_lock abstract_n = Goal.enter_one ~__LOC__ begin fun g -> let sigma, env = Goal.(sigma g, env g) in let l = Evd.fold_undefined (fun e ei l -> - match EConstr.kind sigma (EConstr.of_constr ei.Evd.evar_concl) with + match EConstr.kind sigma ei.Evd.evar_concl with | Term.App(hd, [|ty; n; lock|]) when (not check_lock || (occur_existential_or_casted_meta sigma ty && diff --git a/plugins/ssr/ssrview.ml b/plugins/ssr/ssrview.ml index aa614fbc1..fc50b24a6 100644 --- a/plugins/ssr/ssrview.ml +++ b/plugins/ssr/ssrview.ml @@ -254,7 +254,7 @@ let finalize_view s0 ?(simple_types=true) p = Goal.enter_one ~__LOC__ begin fun g -> let env = Goal.env g in let sigma = Goal.sigma g in - let evars_of_p = Evd.evars_of_term (EConstr.to_constr sigma p) in + let evars_of_p = Evd.evars_of_term (EConstr.to_constr ~abort_on_undefined_evars:false sigma p) in let filter x _ = Evar.Set.mem x evars_of_p in let sigma = Typeclasses.resolve_typeclasses ~fail:false ~filter env sigma in let p = Reductionops.nf_evar sigma p in @@ -265,7 +265,7 @@ Goal.enter_one ~__LOC__ begin fun g -> List.fold_left (fun l k -> if Evd.is_defined sigma k then let bo = get_body Evd.(evar_body (find sigma k)) in - k :: l @ Evar.Set.elements (evars_of_econstr sigma bo) + k :: l @ Evar.Set.elements (evars_of_econstr sigma (EConstr.Unsafe.to_constr bo)) else l ) [] s in let und0 = (* Unassigned evars in the initial goal *) diff --git a/plugins/ssrmatching/ssrmatching.ml4 b/plugins/ssrmatching/ssrmatching.ml4 index 2ba6acc03..a10437a63 100644 --- a/plugins/ssrmatching/ssrmatching.ml4 +++ b/plugins/ssrmatching/ssrmatching.ml4 @@ -283,7 +283,7 @@ exception NoProgress (* comparison can be much faster than the HO one. *) let unif_EQ env sigma p c = - let evars = existential_opt_value sigma, Evd.universes sigma in + let evars = existential_opt_value0 sigma, Evd.universes sigma in try let _ = Reduction.conv env p ~evars c in true with _ -> false let unif_EQ_args env sigma pa a = @@ -337,7 +337,7 @@ let nf_open_term sigma0 ise c = let s = ise and s' = ref sigma0 in let rec nf c' = match kind c' with | Evar ex -> - begin try nf (existential_value s ex) with _ -> + begin try nf (existential_value0 s ex) with _ -> let k, a = ex in let a' = Array.map nf a in if not (Evd.mem !s' k) then s' := Evd.add !s' k (Evarutil.nf_evar_info s (Evd.find s k)); @@ -347,7 +347,9 @@ let nf_open_term sigma0 ise c = let copy_def k evi () = if evar_body evi != Evd.Evar_empty then () else match Evd.evar_body (Evd.find s k) with - | Evar_defined c' -> s' := Evd.define k (nf c') !s' + | Evar_defined c' -> + let c' = EConstr.of_constr (nf (EConstr.Unsafe.to_constr c')) in + s' := Evd.define k c' !s' | _ -> () in let c' = nf c in let _ = Evd.fold copy_def sigma0 () in !s', Evd.evar_universe_context s, EConstr.of_constr c' @@ -446,7 +448,7 @@ let evars_for_FO ~hack env sigma0 (ise0:evar_map) c0 = let nenv = env_size env + if hack then 1 else 0 in let rec put c = match kind c with | Evar (k, a as ex) -> - begin try put (existential_value !sigma ex) + begin try put (existential_value0 !sigma ex) with NotInstantiatedEvar -> if Evd.mem sigma0 k then map put c else let evi = Evd.find !sigma k in @@ -457,11 +459,13 @@ let evars_for_FO ~hack env sigma0 (ise0:evar_map) c0 = | Context.Named.Declaration.LocalAssum (x, t) -> mkVar x :: d, mkNamedProd x (put t) c in let a, t = - Context.Named.fold_inside abs_dc ~init:([], (put evi.evar_concl)) dc in + Context.Named.fold_inside abs_dc + ~init:([], (put @@ EConstr.Unsafe.to_constr evi.evar_concl)) + (EConstr.Unsafe.to_named_context dc) in let m = Evarutil.new_meta () in - ise := meta_declare m t !ise; - sigma := Evd.define k (applistc (mkMeta m) a) !sigma; - put (existential_value !sigma ex) + ise := meta_declare m (EConstr.of_constr t) !ise; + sigma := Evd.define k (EConstr.of_constr (applistc (mkMeta m) a)) !sigma; + put (existential_value0 !sigma ex) end | _ -> map put c in let c1 = put c0 in !ise, c1 @@ -541,7 +545,7 @@ let splay_app ise = | App (f, a') -> loop f (Array.append a' a) | Cast (c', _, _) -> loop c' a | Evar ex -> - (try loop (existential_value ise ex) a with _ -> c, a) + (try loop (existential_value0 ise ex) a with _ -> c, a) | _ -> c, a in fun c -> match kind c with | App (f, a) -> loop f a @@ -1255,7 +1259,7 @@ let eval_pattern ?raise_NoMatch env0 sigma0 concl0 pattern occ do_subst = let fs sigma x = nf_evar sigma x in let pop_evar sigma e p = let { Evd.evar_body = e_body } as e_def = Evd.find sigma e in - let e_body = match e_body with Evar_defined c -> c + let e_body = match e_body with Evar_defined c -> EConstr.Unsafe.to_constr c | _ -> errorstrm (str "Matching the pattern " ++ pr_constr_env env0 sigma0 p ++ str " did not instantiate ?" ++ int (Evar.repr e) ++ spc () ++ str "Does the variable bound by the \"in\" construct occur "++ diff --git a/pretyping/cases.ml b/pretyping/cases.ml index 73be9d6b7..4c87b4e7e 100644 --- a/pretyping/cases.ml +++ b/pretyping/cases.ml @@ -1015,7 +1015,7 @@ let adjust_impossible_cases pb pred tomatch submat = | Evar (evk,_) when snd (evar_source evk !(pb.evdref)) == Evar_kinds.ImpossibleCase -> if not (Evd.is_defined !(pb.evdref) evk) then begin let evd, default = use_unit_judge !(pb.evdref) in - pb.evdref := Evd.define evk (EConstr.Unsafe.to_constr default.uj_type) evd + pb.evdref := Evd.define evk default.uj_type evd end; add_assert_false_case pb tomatch | _ -> @@ -2581,7 +2581,8 @@ let compile_program_cases ?loc style (typing_function, evdref) tycon env lvar let body = it_mkLambda_or_LetIn (applist (j.uj_val, args)) lets in let j = { uj_val = it_mkLambda_or_LetIn body tomatchs_lets; - uj_type = EConstr.of_constr (EConstr.to_constr !evdref tycon); } + (* XXX: is this normalization needed? *) + uj_type = Evarutil.nf_evar !evdref tycon; } in j (**************************************************************************) diff --git a/pretyping/coercion.ml b/pretyping/coercion.ml index 04cb6a59f..6dc3687a0 100644 --- a/pretyping/coercion.ml +++ b/pretyping/coercion.ml @@ -251,7 +251,7 @@ and coerce ?loc env evdref (x : EConstr.constr) (y : EConstr.constr) let (n, dom, rng) = destLambda !evdref t in if isEvar !evdref dom then let (domk, args) = destEvar !evdref dom in - evdref := define domk (EConstr.Unsafe.to_constr a) !evdref; + evdref := define domk a !evdref; else (); t, rng | _ -> raise NoSubtacCoercion diff --git a/pretyping/evarconv.ml b/pretyping/evarconv.ml index d37090a65..144166a34 100644 --- a/pretyping/evarconv.ml +++ b/pretyping/evarconv.ml @@ -114,9 +114,6 @@ let flex_kind_of_term ts env evd c sk = | Fix _ -> Rigid (* happens when the fixpoint is partially applied *) | Cast _ | App _ | Case _ -> assert false -let add_conv_pb (pb, env, x, y) sigma = - Evd.add_conv_pb (pb, env, EConstr.Unsafe.to_constr x, EConstr.Unsafe.to_constr y) sigma - let apprec_nohdbeta ts env evd c = let (t,sk as appr) = Reductionops.whd_nored_state evd (c, []) in if Stack.not_purely_applicative sk @@ -1045,7 +1042,7 @@ let choose_less_dependent_instance evk evd term args = let subst' = List.filter (fun (id,c) -> EConstr.eq_constr evd c term) subst in match subst' with | [] -> None - | (id, _) :: _ -> Some (Evd.define evk (Constr.mkVar id) evd) + | (id, _) :: _ -> Some (Evd.define evk (mkVar id) evd) let apply_on_subterm env evdref f c t = let rec applyrec (env,(k,c) as acc) t = @@ -1085,7 +1082,7 @@ let filter_possible_projections evd c ty ctxt args = let a = Array.unsafe_get args i in (match decl with | NamedDecl.LocalAssum _ -> false - | NamedDecl.LocalDef (_,c,_) -> not (isRel evd (EConstr.of_constr c) || isVar evd (EConstr.of_constr c))) || + | NamedDecl.LocalDef (_,c,_) -> not (isRel evd c || isVar evd c)) || a == c || (* Here we make an approximation, for instance, we could also be *) (* interested in finding a term u convertible to c such that a occurs *) @@ -1135,7 +1132,7 @@ let second_order_matching ts env_rhs evd (evk,args) argoccs rhs = end | decl'::ctxt', c::l, occs::occsl -> let id = NamedDecl.get_id decl' in - let t = EConstr.of_constr (NamedDecl.get_type decl') in + let t = NamedDecl.get_type decl' in let evs = ref [] in let ty = Retyping.get_type_of env_rhs evd c in let filter' = filter_possible_projections evd c ty ctxt args in @@ -1183,7 +1180,7 @@ let second_order_matching ts env_rhs evd (evk,args) argoccs rhs = (* We force abstraction over this unconstrained occurrence *) (* and we use typing to propagate this instantiation *) (* This is an arbitrary choice *) - let evd = Evd.define evk (Constr.mkVar id) evd in + let evd = Evd.define evk (mkVar id) evd in match evar_conv_x ts env_evar evd CUMUL idty evty with | UnifFailure _ -> user_err Pp.(str "Cannot find an instance") | Success evd -> @@ -1205,14 +1202,11 @@ let second_order_matching ts env_rhs evd (evk,args) argoccs rhs = (evar_conv_x full_transparent_state) with IllTypedInstance _ -> raise (TypingFailed evd) in - Evd.define evk (EConstr.Unsafe.to_constr rhs) evd + Evd.define evk rhs evd in abstract_free_holes evd subst, true with TypingFailed evd -> evd, false -let to_pb (pb, env, t1, t2) = - (pb, env, EConstr.Unsafe.to_constr t1, EConstr.Unsafe.to_constr t2) - let second_order_matching_with_args ts env evd pbty ev l t = (* let evd,ev = evar_absorb_arguments env evd ev l in @@ -1222,7 +1216,7 @@ let second_order_matching_with_args ts env evd pbty ev l t = else UnifFailure (evd, ConversionFailed (env,mkApp(mkEvar ev,l),t)) if b then Success evd else *) - let pb = to_pb (pbty,env,mkApp(mkEvar ev,l),t) in + let pb = (pbty,env,mkApp(mkEvar ev,l),t) in UnifFailure (evd, CannotSolveConstraint (pb,ProblemBeyondCapabilities)) let apply_conversion_problem_heuristic ts env evd pbty t1 t2 = @@ -1245,7 +1239,7 @@ let apply_conversion_problem_heuristic ts env evd pbty t1 t2 = | Some evd -> Success evd | None -> let reason = ProblemBeyondCapabilities in - UnifFailure (evd, CannotSolveConstraint (to_pb (pbty,env,t1,t2),reason))) + UnifFailure (evd, CannotSolveConstraint ((pbty,env,t1,t2),reason))) | (Rel _|Var _), Evar (evk2,args2) when app_empty && List.for_all (fun a -> EConstr.eq_constr evd a term1 || isEvar evd a) (remove_instance_local_defs evd evk2 args2) -> @@ -1255,7 +1249,7 @@ let apply_conversion_problem_heuristic ts env evd pbty t1 t2 = | Some evd -> Success evd | None -> let reason = ProblemBeyondCapabilities in - UnifFailure (evd, CannotSolveConstraint (to_pb (pbty,env,t1,t2),reason))) + UnifFailure (evd, CannotSolveConstraint ((pbty,env,t1,t2),reason))) | Evar (evk1,args1), Evar (evk2,args2) when Evar.equal evk1 evk2 -> let f env evd pbty x y = is_fconv ~reds:ts pbty env evd x y in Success (solve_refl ~can_drop:true f env evd @@ -1295,10 +1289,10 @@ let error_cannot_unify env evd pb ?reason t1 t2 = let check_problems_are_solved env evd = match snd (extract_all_conv_pbs evd) with - | (pbty,env,t1,t2) as pb::_ -> error_cannot_unify env evd pb (EConstr.of_constr t1) (EConstr.of_constr t2) + | (pbty,env,t1,t2) as pb::_ -> error_cannot_unify env evd pb t1 t2 | _ -> () -exception MaxUndefined of (Evar.t * evar_info * Constr.t list) +exception MaxUndefined of (Evar.t * evar_info * EConstr.t list) let max_undefined_with_candidates evd = let fold evk evi () = match evi.evar_candidates with @@ -1326,7 +1320,7 @@ let rec solve_unconstrained_evars_with_candidates ts evd = | a::l -> try let conv_algo = evar_conv_x ts in - let evd = check_evar_instance evd evk (EConstr.of_constr a) conv_algo in + let evd = check_evar_instance evd evk a conv_algo in let evd = Evd.define evk a evd in match reconsider_unif_constraints conv_algo evd with | Success evd -> solve_unconstrained_evars_with_candidates ts evd @@ -1348,7 +1342,7 @@ let solve_unconstrained_impossible_cases env evd = let ty = j_type j in let conv_algo = evar_conv_x full_transparent_state in let evd' = check_evar_instance evd' evk ty conv_algo in - Evd.define evk (EConstr.Unsafe.to_constr ty) evd' + Evd.define evk ty evd' | _ -> evd') evd evd let solve_unif_constraints_with_heuristics env @@ -1357,8 +1351,6 @@ let solve_unif_constraints_with_heuristics env let rec aux evd pbs progress stuck = match pbs with | (pbty,env,t1,t2 as pb) :: pbs -> - let t1 = EConstr.of_constr t1 in - let t2 = EConstr.of_constr t2 in (match apply_conversion_problem_heuristic ts env evd pbty t1 t2 with | Success evd' -> let (evd', rest) = extract_all_conv_pbs evd' in @@ -1375,9 +1367,7 @@ let solve_unif_constraints_with_heuristics env match stuck with | [] -> (* We're finished *) evd | (pbty,env,t1,t2 as pb) :: _ -> - let t1 = EConstr.of_constr t1 in - let t2 = EConstr.of_constr t2 in - (* There remains stuck problems *) + (* There remains stuck problems *) error_cannot_unify env evd pb t1 t2 in let (evd,pbs) = extract_all_conv_pbs evd in diff --git a/pretyping/evardefine.ml b/pretyping/evardefine.ml index 4cffbbb83..b452755b1 100644 --- a/pretyping/evardefine.ml +++ b/pretyping/evardefine.ml @@ -77,7 +77,7 @@ let define_pure_evar_as_product evd evk = let evi = Evd.find_undefined evd evk in let evenv = evar_env evi in let id = next_ident_away idx (Environ.ids_of_named_context_val evi.evar_hyps) in - let concl = Reductionops.whd_all evenv evd (EConstr.of_constr evi.evar_concl) in + let concl = Reductionops.whd_all evenv evd evi.evar_concl in let s = destSort evd concl in let evksrc = evar_source evk evd in let src = subterm_source evk ~where:Domain evksrc in @@ -101,7 +101,7 @@ let define_pure_evar_as_product evd evk = evd3, rng in let prod = mkProd (Name id, dom, subst_var id rng) in - let evd3 = Evd.define evk (EConstr.Unsafe.to_constr prod) evd2 in + let evd3 = Evd.define evk prod evd2 in evd3,prod (* Refine an applied evar to a product and returns its instantiation *) @@ -128,7 +128,7 @@ let define_pure_evar_as_lambda env evd evk = let open Context.Named.Declaration in let evi = Evd.find_undefined evd evk in let evenv = evar_env evi in - let typ = Reductionops.whd_all evenv evd (EConstr.of_constr (evar_concl evi)) in + let typ = Reductionops.whd_all evenv evd (evar_concl evi) in let evd1,(na,dom,rng) = match EConstr.kind evd typ with | Prod (na,dom,rng) -> (evd,(na,dom,rng)) | Evar ev' -> let evd,typ = define_evar_as_product evd ev' in evd,destProd evd typ @@ -141,7 +141,7 @@ let define_pure_evar_as_lambda env evd evk = let src = subterm_source evk ~where:Body (evar_source evk evd1) in let evd2,body = new_evar newenv evd1 ~src (subst1 (mkVar id) rng) ~filter in let lam = mkLambda (Name id, dom, subst_var id body) in - Evd.define evk (EConstr.Unsafe.to_constr lam) evd2, lam + Evd.define evk lam evd2, lam let define_evar_as_lambda env evd (evk,args) = let evd,lam = define_pure_evar_as_lambda env evd evk in @@ -166,9 +166,9 @@ let define_evar_as_sort env evd (ev,args) = let evd, u = new_univ_variable univ_rigid evd in let evi = Evd.find_undefined evd ev in let s = Type u in - let concl = Reductionops.whd_all (evar_env evi) evd (EConstr.of_constr evi.evar_concl) in + let concl = Reductionops.whd_all (evar_env evi) evd evi.evar_concl in let sort = destSort evd concl in - let evd' = Evd.define ev (Constr.mkSort s) evd in + let evd' = Evd.define ev (mkSort s) evd in Evd.set_leq_sort env evd' (Type (Univ.super u)) (ESorts.kind evd' sort), s (* Propagation of constraints through application and abstraction: diff --git a/pretyping/evarsolve.ml b/pretyping/evarsolve.ml index 96d80741a..b7eaff078 100644 --- a/pretyping/evarsolve.ml +++ b/pretyping/evarsolve.ml @@ -89,9 +89,9 @@ let refresh_universes ?(status=univ_rigid) ?(onlyalg=false) ?(refreshset=false) Array.iter (refresh_term_evars onevars false) args | Evar (ev, a) when onevars -> let evi = Evd.find !evdref ev in - let ty' = refresh ~onlyalg univ_flexible ~direction:true (EConstr.of_constr evi.evar_concl) in + let ty' = refresh ~onlyalg univ_flexible ~direction:true evi.evar_concl in if !modified then - evdref := Evd.add !evdref ev {evi with evar_concl = EConstr.Unsafe.to_constr ty'} + evdref := Evd.add !evdref ev {evi with evar_concl = ty'} else () | _ -> EConstr.iter !evdref (refresh_term_evars onevars false) t and refresh_polymorphic_positions args pos = @@ -137,8 +137,6 @@ let test_success conv_algo env evd c c' rhs = is_success (conv_algo env evd c c' rhs) let add_conv_oriented_pb ?(tail=true) (pbty,env,t1,t2) evd = - let t1 = EConstr.Unsafe.to_constr t1 in - let t2 = EConstr.Unsafe.to_constr t2 in match pbty with | Some true -> add_conv_pb ~tail (Reduction.CUMUL,env,t1,t2) evd | Some false -> add_conv_pb ~tail (Reduction.CUMUL,env,t2,t1) evd @@ -197,7 +195,7 @@ let restrict_evar_key evd evk filter candidates = | None -> evar_filter evi | Some filter -> filter in let candidates = match candidates with - | NoUpdate -> Option.map (fun l -> List.map EConstr.of_constr l) evi.evar_candidates + | NoUpdate -> evi.evar_candidates | UpdateWith c -> Some c in restrict_evar evd evk filter candidates end @@ -600,7 +598,6 @@ let solve_pattern_eqn env sigma l c = let make_projectable_subst aliases sigma evi args = let sign = evar_filtered_context evi in - let sign = List.map (fun d -> map_named_decl EConstr.of_constr d) sign in let evar_aliases = compute_var_aliases sign sigma in let (_,full_subst,cstr_subst) = List.fold_right @@ -877,7 +874,7 @@ let choose_projection evi sols = let rec do_projection_effects define_fun env ty evd = function | ProjectVar -> evd | ProjectEvar ((evk,argsv),evi,id,p) -> - let evd = Evd.define evk (Constr.mkVar id) evd in + let evd = Evd.define evk (mkVar id) evd in (* TODO: simplify constraints involving evk *) let evd = do_projection_effects define_fun env ty evd p in let ty = whd_all env evd (Lazy.force ty) in @@ -887,7 +884,7 @@ let rec do_projection_effects define_fun env ty evd = function one (however, regarding coercions, because t is obtained by unif, we know that no coercion can be inserted) *) let subst = make_pure_subst evi argsv in - let ty' = replace_vars subst (EConstr.of_constr evi.evar_concl) in + let ty' = replace_vars subst evi.evar_concl in if isEvar evd ty' then define_fun env evd (Some false) (destEvar evd ty') ty else evd else evd @@ -1004,7 +1001,7 @@ let filter_effective_candidates evd evi filter candidates = let filter_candidates evd evk filter candidates_update = let evi = Evd.find_undefined evd evk in let candidates = match candidates_update with - | NoUpdate -> Option.map (fun l -> List.map EConstr.of_constr l) evi.evar_candidates + | NoUpdate -> evi.evar_candidates | UpdateWith c -> Some c in match candidates with @@ -1023,13 +1020,12 @@ let closure_of_filter evd evk = function | None -> None | Some filter -> let evi = Evd.find_undefined evd evk in - let vars = collect_vars evd (EConstr.of_constr (evar_concl evi)) in + let vars = collect_vars evd (evar_concl evi) in let test b decl = b || Id.Set.mem (get_id decl) vars || match decl with | LocalAssum _ -> false | LocalDef (_,c,_) -> - let c = EConstr.of_constr c in not (isRel evd c || isVar evd c) in let newfilter = Filter.map_along test filter (evar_context evi) in @@ -1062,7 +1058,7 @@ let do_restrict_hyps evd (evk,args as ev) filter candidates = match candidates,filter with | UpdateWith [], _ -> user_err Pp.(str "Not solvable.") | UpdateWith [nc],_ -> - let evd = Evd.define evk (EConstr.Unsafe.to_constr nc) evd in + let evd = Evd.define evk nc evd in raise (EvarSolvedWhileRestricting (evd,mkEvar ev)) | NoUpdate, None -> evd,ev | _ -> restrict_applied_evar evd ev filter candidates @@ -1113,9 +1109,6 @@ let postpone_non_unique_projection env evd pbty (evk,argsv as ev) sols rhs = * Note: argument f is the function used to instantiate evars. *) -let instantiate_evar_array evi c args = - EConstr.of_constr (instantiate_evar_array evi (EConstr.Unsafe.to_constr c) (Array.map EConstr.Unsafe.to_constr args)) - let filter_compatible_candidates conv_algo env evd evi args rhs c = let c' = instantiate_evar_array evi c args in match conv_algo env evd Reduction.CONV rhs c' with @@ -1135,8 +1128,6 @@ let restrict_candidates conv_algo env evd filter1 (evk1,argsv1) (evk2,argsv2) = | _, None -> filter_candidates evd evk1 filter1 NoUpdate | None, Some _ -> raise DoesNotPreserveCandidateRestriction | Some l1, Some l2 -> - let l1 = List.map EConstr.of_constr l1 in - let l2 = List.map EConstr.of_constr l2 in let l1 = filter_effective_candidates evd evi1 filter1 l1 in let l1' = List.filter (fun c1 -> let c1' = instantiate_evar_array evi1 c1 argsv1 in @@ -1242,9 +1233,9 @@ let check_evar_instance evd evk1 body conv_algo = try Retyping.get_type_of ~lax:true evenv evd body with Retyping.RetypeError _ -> user_err Pp.(str "Ill-typed evar instance") in - match conv_algo evenv evd Reduction.CUMUL ty (EConstr.of_constr evi.evar_concl) with + match conv_algo evenv evd Reduction.CUMUL ty evi.evar_concl with | Success evd -> evd - | UnifFailure _ -> raise (IllTypedInstance (evenv,ty,EConstr.of_constr evi.evar_concl)) + | UnifFailure _ -> raise (IllTypedInstance (evenv,ty, evi.evar_concl)) let update_evar_source ev1 ev2 evd = let loc, evs2 = evar_source ev2 evd in @@ -1257,7 +1248,7 @@ let update_evar_source ev1 ev2 evd = let solve_evar_evar_l2r force f g env evd aliases pbty ev1 (evk2,_ as ev2) = try let evd,body = project_evar_on_evar force g env evd aliases 0 pbty ev1 ev2 in - let evd' = Evd.define evk2 (EConstr.Unsafe.to_constr body) evd in + let evd' = Evd.define evk2 body evd in let evd' = update_evar_source (fst (destEvar evd body)) evk2 evd' in check_evar_instance evd' evk2 body g with EvarSolvedOnTheFly (evd,c) -> @@ -1292,17 +1283,19 @@ let solve_evar_evar_aux force f g env evd pbty (evk1,args1 as ev1) (evk2,args2 a let solve_evar_evar ?(force=false) f g env evd pbty (evk1,args1 as ev1) (evk2,args2 as ev2) = let pbty = if force then None else pbty in let evi = Evd.find evd evk1 in - let downcast evk t evd = downcast evk (EConstr.Unsafe.to_constr t) evd in + let downcast evk t evd = downcast evk t evd in let evd = try (* ?X : Π Δ. Type i = ?Y : Π Δ'. Type j. The body of ?X and ?Y just has to be of type Π Δ. Type k for some k <= i, j. *) let evienv = Evd.evar_env evi in - let ctx1, i = Reduction.dest_arity evienv evi.evar_concl in + let concl1 = EConstr.Unsafe.to_constr evi.evar_concl in + let ctx1, i = Reduction.dest_arity evienv concl1 in let ctx1 = List.map (fun c -> map_rel_decl EConstr.of_constr c) ctx1 in let evi2 = Evd.find evd evk2 in let evi2env = Evd.evar_env evi2 in - let ctx2, j = Reduction.dest_arity evi2env evi2.evar_concl in + let concl2 = EConstr.Unsafe.to_constr evi2.evar_concl in + let ctx2, j = Reduction.dest_arity evi2env concl2 in let ctx2 = List.map (fun c -> map_rel_decl EConstr.of_constr c) ctx2 in let ui, uj = univ_of_sort i, univ_of_sort j in if i == j || Evd.check_eq evd ui uj @@ -1375,14 +1368,14 @@ let solve_candidates conv_algo env evd (evk,argsv) rhs = | Some l -> let l' = List.map_filter - (fun c -> filter_compatible_candidates conv_algo env evd evi argsv rhs (EConstr.of_constr c)) l in + (fun c -> filter_compatible_candidates conv_algo env evd evi argsv rhs c) l in match l' with | [] -> raise IncompatibleCandidates | [c,evd] -> (* solve_candidates might have been called recursively in the mean *) (* time and the evar been solved by the filtering process *) if Evd.is_undefined evd evk then - let evd' = Evd.define evk (EConstr.Unsafe.to_constr c) evd in + let evd' = Evd.define evk c evd in check_evar_instance evd' evk c conv_algo else evd | l when List.length l < List.length l' -> @@ -1401,8 +1394,8 @@ let occur_evar_upto_types sigma n c = Array.iter occur_rec args else ( seen := Evar.Set.add sp !seen; - Option.iter occur_rec (existential_opt_value sigma e); - occur_rec (Evd.existential_type sigma e)) + Option.iter occur_rec (existential_opt_value0 sigma e); + occur_rec (Evd.existential_type0 sigma e)) | _ -> Constr.iter occur_rec c in try occur_rec c; false with Occur -> true @@ -1529,7 +1522,7 @@ let rec invert_definition conv_algo choose env evd pbty (evk,argsv as ev) rhs = (* Try to project (a restriction of) the left evar ... *) try let evd,body = project_evar_on_evar false conv_algo env' evd aliases 0 None ev'' ev' in - let evd = Evd.define evk' (EConstr.Unsafe.to_constr body) evd in + let evd = Evd.define evk' body evd in check_evar_instance evd evk' body conv_algo with | EvarSolvedOnTheFly _ -> assert false (* ev has no candidates *) @@ -1592,14 +1585,14 @@ let rec invert_definition conv_algo choose env evd pbty (evk,argsv as ev) rhs = Id.Set.subset (collect_vars evd rhs) !names in let body = - if fast rhs then EConstr.of_constr (EConstr.to_constr evd rhs) (** FIXME? *) + if fast rhs then nf_evar evd rhs (** FIXME? *) else let t' = imitate (env,0) rhs in if !progress then (recheck_applications conv_algo (evar_env evi) evdref t'; t') else t' in (!evdref,body) - + (* [define] tries to solve the problem "?ev[args] = rhs" when "?ev" is * an (uninstantiated) evar such that "hyps |- ?ev : typ". Otherwise said, * [define] tries to find an instance lhs such that @@ -1644,7 +1637,7 @@ and evar_define conv_algo ?(choose=false) env evd pbty (evk,argsv as ev) rhs = print_constr body); raise e in*) let evd' = check_evar_instance evd' evk body conv_algo in - Evd.define evk (EConstr.Unsafe.to_constr body) evd' + Evd.define evk body evd' with | NotEnoughInformationToProgress sols -> postpone_non_unique_projection env evd pbty ev sols rhs @@ -1691,8 +1684,6 @@ and evar_define conv_algo ?(choose=false) env evd pbty (evk,argsv as ev) rhs = *) let status_changed evd lev (pbty,_,t1,t2) = - let t1 = EConstr.of_constr t1 in - let t2 = EConstr.of_constr t2 in (try Evar.Set.mem (head_evar evd t1) lev with NoHeadEvar -> false) || (try Evar.Set.mem (head_evar evd t2) lev with NoHeadEvar -> false) @@ -1702,7 +1693,7 @@ let reconsider_unif_constraints conv_algo evd = (fun p (pbty,env,t1,t2 as x) -> match p with | Success evd -> - (match conv_algo env evd pbty (EConstr.of_constr t1) (EConstr.of_constr t2) with + (match conv_algo env evd pbty t1 t2 with | Success _ as x -> x | UnifFailure (i,e) -> UnifFailure (i,CannotSolveConstraint (x,e))) | UnifFailure _ as x -> x) diff --git a/pretyping/nativenorm.ml b/pretyping/nativenorm.ml index fcbf50fea..85911394f 100644 --- a/pretyping/nativenorm.ml +++ b/pretyping/nativenorm.ml @@ -401,9 +401,9 @@ and nf_evar env sigma evk ty args = mkEvar (evk, Array.of_list args), ty let evars_of_evar_map sigma = - { Nativelambda.evars_val = Evd.existential_opt_value sigma; - Nativelambda.evars_typ = Evd.existential_type sigma; - Nativelambda.evars_metas = Evd.meta_type sigma } + { Nativelambda.evars_val = Evd.existential_opt_value0 sigma; + Nativelambda.evars_typ = Evd.existential_type0 sigma; + Nativelambda.evars_metas = Evd.meta_type0 sigma } (* fork perf process, return profiler's process id *) let start_profiler_linux profile_fn = diff --git a/pretyping/patternops.ml b/pretyping/patternops.ml index e52112fda..27e457e3b 100644 --- a/pretyping/patternops.ml +++ b/pretyping/patternops.ml @@ -184,7 +184,7 @@ let pattern_of_constr env sigma t = | Evar_kinds.GoalEvar | Evar_kinds.VarInstance _ -> (* These are the two evar kinds used for existing goals *) (* see Proofview.mark_in_evm *) - if Evd.is_defined sigma evk then pattern_of_constr env (Evd.existential_value sigma ev) + if Evd.is_defined sigma evk then pattern_of_constr env (Evd.existential_value0 sigma ev) else PEvar (evk,Array.map (pattern_of_constr env) ctxt) | Evar_kinds.MatchingVar (Evar_kinds.SecondOrderPatVar ido) -> assert false | _ -> diff --git a/pretyping/pretyping.ml b/pretyping/pretyping.ml index 4962b89a0..947469ca0 100644 --- a/pretyping/pretyping.ml +++ b/pretyping/pretyping.ml @@ -117,7 +117,7 @@ open ExtraEnv exception Found of int array let nf_fix sigma (nas, cs, ts) = - let inj c = EConstr.to_constr sigma c in + let inj c = EConstr.to_constr ~abort_on_undefined_evars:false sigma c in (nas, Array.map inj cs, Array.map inj ts) let search_guard ?loc env possible_indexes fixdefs = @@ -315,7 +315,7 @@ let apply_inference_hook hook evdref frozen = match frozen with then try let sigma, c = hook sigma evk in - Evd.define evk (EConstr.Unsafe.to_constr c) sigma + Evd.define evk c sigma with Exit -> sigma else @@ -532,7 +532,7 @@ let pretype_global ?loc rigid env evd gr us = interp_instance ?loc evd ~len l in let (sigma, c) = Evd.fresh_global ?loc ~rigid ?names:instance env.ExtraEnv.env evd gr in - (sigma, EConstr.of_constr c) + (sigma, c) let pretype_ref ?loc evdref env ref us = match ref with @@ -1109,7 +1109,7 @@ let rec pretype k0 resolve_tc (tycon : type_constraint) (env : ExtraEnv.t) evdre and pretype_instance k0 resolve_tc env evdref lvar loc hyps evk update = let f decl (subst,update) = let id = NamedDecl.get_id decl in - let t = replace_vars subst (EConstr.of_constr (NamedDecl.get_type decl)) in + let t = replace_vars subst (NamedDecl.get_type decl) in let c, update = try let c = List.assoc id update in @@ -1150,7 +1150,7 @@ and pretype_type k0 resolve_tc valcon (env : ExtraEnv.t) evdref lvar c = match D (* Correction of bug #5315 : we need to define an evar for *all* holes *) let evkt = e_new_evar env evdref ~src:(loc, knd) ~naming (mkSort s) in let ev,_ = destEvar !evdref evkt in - evdref := Evd.define ev (to_constr !evdref v) !evdref; + evdref := Evd.define ev (nf_evar !evdref v) !evdref; (* End of correction of bug #5315 *) { utj_val = v; utj_type = s } diff --git a/pretyping/reductionops.ml b/pretyping/reductionops.ml index 360c6e86e..244b8e60b 100644 --- a/pretyping/reductionops.ml +++ b/pretyping/reductionops.ml @@ -871,7 +871,7 @@ let rec whd_state_gen ?csts ~refold ~tactic_mode flags env sigma = | Evar ev -> fold () | Meta ev -> (match safe_meta_value sigma ev with - | Some body -> whrec cst_l (EConstr.of_constr body, stack) + | Some body -> whrec cst_l (body, stack) | None -> fold ()) | Const (c,u as const) -> reduction_effect_hook env sigma (EConstr.to_constr sigma x) @@ -1106,7 +1106,7 @@ let local_whd_state_gen flags sigma = | Evar ev -> s | Meta ev -> (match safe_meta_value sigma ev with - Some c -> whrec (EConstr.of_constr c,stack) + Some c -> whrec (c,stack) | None -> s) | Construct ((ind,c),u) -> @@ -1392,7 +1392,7 @@ let vm_infer_conv ?(pb=Reduction.CUMUL) env t1 t2 = (********************************************************************) let whd_meta sigma c = match EConstr.kind sigma c with - | Meta p -> (try EConstr.of_constr (meta_value sigma p) with Not_found -> c) + | Meta p -> (try meta_value sigma p with Not_found -> c) | _ -> c let default_plain_instance_ident = Id.of_string "H" @@ -1612,7 +1612,7 @@ let meta_value evd mv = match meta_opt_fvalue evd mv with | Some (b,_) -> let metas = Metamap.bind valrec b.freemetas in - instance evd metas (EConstr.of_constr b.rebus) + instance evd metas b.rebus | None -> mkMeta mv in valrec mv @@ -1625,9 +1625,8 @@ let meta_instance sigma b = instance sigma c_sigma b.rebus let nf_meta sigma c = - let c = EConstr.Unsafe.to_constr c in let cl = mk_freelisted c in - meta_instance sigma { cl with rebus = EConstr.of_constr cl.rebus } + meta_instance sigma { cl with rebus = cl.rebus } (* Instantiate metas that create beta/iota redexes *) @@ -1648,7 +1647,6 @@ let meta_reducible_instance evd b = (match try let g, s = Metamap.find m metas in - let g = EConstr.of_constr g in let is_coerce = match s with CoerceToType -> true | _ -> false in if isConstruct evd g || not is_coerce then Some g else None with Not_found -> None @@ -1660,7 +1658,6 @@ let meta_reducible_instance evd b = (match try let g, s = Metamap.find m metas in - let g = EConstr.of_constr g in let is_coerce = match s with CoerceToType -> true | _ -> false in if isLambda evd g || not is_coerce then Some g else None with Not_found -> None @@ -1669,7 +1666,6 @@ let meta_reducible_instance evd b = | None -> mkApp (f,Array.map irec l)) | Meta m -> (try let g, s = Metamap.find m metas in - let g = EConstr.of_constr g in let is_coerce = match s with CoerceToType -> true | _ -> false in if not is_coerce then irec g else u with Not_found -> u) @@ -1678,7 +1674,6 @@ let meta_reducible_instance evd b = (match try let g, s = Metamap.find m metas in - let g = EConstr.of_constr g in let is_coerce = match s with CoerceToType -> true | _ -> false in if isConstruct evd g || not is_coerce then Some g else None with Not_found -> None diff --git a/pretyping/retyping.ml b/pretyping/retyping.ml index 3582b6447..746a68b21 100644 --- a/pretyping/retyping.ml +++ b/pretyping/retyping.ml @@ -57,8 +57,8 @@ let get_type_from_constraints env sigma t = if isEvar sigma (fst (decompose_app_vect sigma t)) then match List.map_filter (fun (pbty,env,t1,t2) -> - if is_fconv Reduction.CONV env sigma t (EConstr.of_constr t1) then Some t2 - else if is_fconv Reduction.CONV env sigma t (EConstr.of_constr t2) then Some t1 + if is_fconv Reduction.CONV env sigma t t1 then Some t2 + else if is_fconv Reduction.CONV env sigma t t2 then Some t1 else None) (snd (Evd.extract_all_conv_pbs sigma)) with @@ -99,7 +99,7 @@ let retype ?(polyprop=true) sigma = let rec type_of env cstr = match EConstr.kind sigma cstr with | Meta n -> - (try strip_outer_cast sigma (EConstr.of_constr (Evd.meta_ftype sigma n).Evd.rebus) + (try strip_outer_cast sigma (Evd.meta_ftype sigma n).Evd.rebus with Not_found -> retype_error (BadMeta n)) | Rel n -> let ty = RelDecl.get_type (lookup_rel n env) in @@ -115,7 +115,7 @@ let retype ?(polyprop=true) sigma = try Inductiveops.find_rectype env sigma t with Not_found -> try - let t = EConstr.of_constr (get_type_from_constraints env sigma t) in + let t = get_type_from_constraints env sigma t in Inductiveops.find_rectype env sigma t with Not_found -> retype_error BadRecursiveType in @@ -170,7 +170,7 @@ let retype ?(polyprop=true) sigma = and type_of_global_reference_knowing_parameters env c args = let argtyps = - Array.map (fun c -> lazy (EConstr.to_constr sigma (type_of env c))) args in + Array.map (fun c -> lazy (EConstr.to_constr ~abort_on_undefined_evars:false sigma (type_of env c))) args in match EConstr.kind sigma c with | Ind (ind, u) -> let u = EInstance.kind sigma u in diff --git a/pretyping/tacred.ml b/pretyping/tacred.ml index 518d2f604..696001ab7 100644 --- a/pretyping/tacred.ml +++ b/pretyping/tacred.ml @@ -416,7 +416,7 @@ exception Partial reduction is solved by the expanded fix term. *) let solve_arity_problem env sigma fxminargs c = let evm = ref sigma in - let set_fix i = evm := Evd.define i (Constr.mkVar vfx) !evm in + let set_fix i = evm := Evd.define i (mkVar vfx) !evm in let rec check strict c = let c' = whd_betaiotazeta sigma c in let (h,rcargs) = decompose_app_vect sigma c' in @@ -558,7 +558,7 @@ let match_eval_ref_value env sigma constr stack = else None | Proj (p, c) when not (Projection.unfolded p) -> - reduction_effect_hook env sigma (EConstr.to_constr sigma constr) + reduction_effect_hook env sigma (EConstr.to_constr ~abort_on_undefined_evars:false sigma constr) (lazy (EConstr.to_constr sigma (applist (constr,stack)))); if is_evaluable env (EvalConstRef (Projection.constant p)) then Some (mkProj (Projection.unfold p, c)) @@ -641,7 +641,7 @@ let whd_nothing_for_iota env sigma s = | _ -> s) | Evar ev -> s | Meta ev -> - (try whrec (EConstr.of_constr (Evd.meta_value sigma ev), stack) + (try whrec (Evd.meta_value sigma ev, stack) with Not_found -> s) | Const (const, u) when is_transparent_constant full_transparent_state const -> let u = EInstance.kind sigma u in diff --git a/pretyping/typeclasses.ml b/pretyping/typeclasses.ml index 08051fd3a..30ddeffa6 100644 --- a/pretyping/typeclasses.ml +++ b/pretyping/typeclasses.ml @@ -158,7 +158,7 @@ let rec is_class_type evd c = | _ -> is_class_constr evd c let is_class_evar evd evi = - is_class_type evd (EConstr.of_constr evi.Evd.evar_concl) + is_class_type evd evi.Evd.evar_concl (* * classes persistent object diff --git a/pretyping/typing.ml b/pretyping/typing.ml index 4c834f2f8..aaec73f04 100644 --- a/pretyping/typing.ml +++ b/pretyping/typing.ml @@ -29,13 +29,12 @@ let meta_type evd mv = let ty = try Evd.meta_ftype evd mv with Not_found -> anomaly (str "unknown meta ?" ++ str (Nameops.string_of_meta mv) ++ str ".") in - let ty = Evd.map_fl EConstr.of_constr ty in meta_instance evd ty let inductive_type_knowing_parameters env sigma (ind,u) jl = let u = Unsafe.to_instance u in let mspec = lookup_mind_specif env ind in - let paramstyp = Array.map (fun j -> lazy (EConstr.to_constr sigma j.uj_type)) jl in + let paramstyp = Array.map (fun j -> lazy (EConstr.to_constr ~abort_on_undefined_evars:false sigma j.uj_type)) jl in Inductive.type_of_inductive_knowing_parameters env (mspec,u) paramstyp let e_type_judgment env evdref j = @@ -129,7 +128,7 @@ let e_is_correct_arity env evdref c pj ind specif params = then error () | Evar (ev,_), [] -> let evd, s = Evd.fresh_sort_in_family env !evdref (max_sort allowed_sorts) in - evdref := Evd.define ev (Constr.mkSort s) evd + evdref := Evd.define ev (mkSort s) evd | _, (LocalDef _ as d)::ar' -> srec (push_rel d env) (lift 1 pt') ar' | _ -> @@ -155,7 +154,7 @@ let e_type_case_branches env evdref (ind,largs) pj c = let p = pj.uj_val in let params = List.map EConstr.Unsafe.to_constr params in let () = e_is_correct_arity env evdref c pj ind specif params in - let lc = build_branches_type ind specif params (EConstr.to_constr !evdref p) in + let lc = build_branches_type ind specif params (EConstr.to_constr ~abort_on_undefined_evars:false !evdref p) in let lc = Array.map EConstr.of_constr lc in let n = (snd specif).Declarations.mind_nrealdecls in let ty = whd_betaiota !evdref (lambda_applist_assum !evdref (n+1) p (realargs@[c])) in @@ -207,7 +206,7 @@ let enrich_env env evdref = Environ.env_of_pre_env penv' let check_fix env sigma pfix = - let inj c = EConstr.to_constr sigma c in + let inj c = EConstr.to_constr ~abort_on_undefined_evars:false sigma c in let (idx, (ids, cs, ts)) = pfix in check_fix env (idx, (ids, Array.map inj cs, Array.map inj ts)) diff --git a/pretyping/unification.ml b/pretyping/unification.ml index ca03b96ab..d98ce9aba 100644 --- a/pretyping/unification.ml +++ b/pretyping/unification.ml @@ -84,7 +84,7 @@ let occur_meta_or_undefined_evar evd c = | Evar (ev,args) -> (match evar_body (Evd.find evd ev) with | Evar_defined c -> - occrec c; Array.iter occrec args + occrec (EConstr.Unsafe.to_constr c); Array.iter occrec args | Evar_empty -> raise Occur) | _ -> Constr.iter occrec c in try occrec c; false with Occur | Not_found -> true @@ -189,10 +189,9 @@ let pose_all_metas_as_evars env evd t = let rec aux t = match EConstr.kind !evdref t with | Meta mv -> (match Evd.meta_opt_fvalue !evdref mv with - | Some ({rebus=c},_) -> EConstr.of_constr c + | Some ({rebus=c},_) -> c | None -> let {rebus=ty;freemetas=mvs} = Evd.meta_ftype evd mv in - let ty = EConstr.of_constr ty in let ty = if Evd.Metaset.is_empty mvs then ty else aux ty in let ty = if Flags.version_strictly_greater Flags.V8_6 @@ -200,7 +199,7 @@ let pose_all_metas_as_evars env evd t = else ty (* some beta-iota-normalization "regression" in 8.5 and 8.6 *) in let src = Evd.evar_source_of_meta mv !evdref in let ev = Evarutil.e_new_evar env evdref ~src ty in - evdref := meta_assign mv (EConstr.Unsafe.to_constr ev,(Conv,TypeNotProcessed)) !evdref; + evdref := meta_assign mv (ev,(Conv,TypeNotProcessed)) !evdref; ev) | _ -> EConstr.map !evdref aux t in @@ -1060,7 +1059,7 @@ let rec unify_0_with_initial_metas (sigma,ms,es as subst : subst0) conv_at_top e (evd,t2::ks, m-1) else let mv = new_meta () in - let evd' = meta_declare mv (EConstr.Unsafe.to_constr (substl ks b)) evd in + let evd' = meta_declare mv (substl ks b) evd in (evd', mkMeta mv :: ks, m - 1)) (sigma,[],List.length bs) bs in @@ -1247,7 +1246,7 @@ let try_to_coerce env evd c cty tycon = let j = make_judge c cty in let (evd',j') = inh_conv_coerce_rigid_to true env evd j tycon in let evd' = Evarconv.solve_unif_constraints_with_heuristics env evd' in - let evd' = Evd.map_metas_fvalue (fun c -> EConstr.Unsafe.to_constr (nf_evar evd' (EConstr.of_constr c))) evd' in + let evd' = Evd.map_metas_fvalue (fun c -> nf_evar evd' c) evd' in (evd',j'.uj_val) let w_coerce_to_type env evd c cty mvty = @@ -1359,11 +1358,11 @@ let w_merge env with_types flags (evd,metas,evars : subst0) = if meta_defined evd mv then let {rebus=c'},(status',_) = meta_fvalue evd mv in let (take_left,st,(evd,metas',evars')) = - merge_instances env evd flags status' status (EConstr.of_constr c') c + merge_instances env evd flags status' status c' c in let evd' = if take_left then evd - else meta_reassign mv (EConstr.Unsafe.to_constr c,(st,TypeProcessed)) evd + else meta_reassign mv (c,(st,TypeProcessed)) evd in w_merge_rec evd' (metas'@metas@metas'') (evars'@evars'') eqns else @@ -1372,7 +1371,7 @@ let w_merge env with_types flags (evd,metas,evars : subst0) = if isMetaOf evd mv (whd_all env evd c) then evd else error_cannot_unify env evd (mkMeta mv,c) else - meta_assign mv (EConstr.Unsafe.to_constr c,(status,TypeProcessed)) evd in + meta_assign mv (c,(status,TypeProcessed)) evd in w_merge_rec evd' (metas''@metas) evars'' eqns | [] -> (* Process type eqns *) @@ -1396,17 +1395,17 @@ let w_merge env with_types flags (evd,metas,evars : subst0) = let (evd', c) = applyHead sp_env evd nargs hdc in let (evd'',mc,ec) = unify_0 sp_env evd' CUMUL flags - (get_type_of sp_env evd' c) (EConstr.of_constr ev.evar_concl) in + (get_type_of sp_env evd' c) ev.evar_concl in let evd''' = w_merge_rec evd'' mc ec [] in if evd' == evd''' - then Evd.define sp (EConstr.Unsafe.to_constr c) evd''' - else Evd.define sp (EConstr.Unsafe.to_constr (Evarutil.nf_evar evd''' c)) evd''' in + then Evd.define sp c evd''' + else Evd.define sp (Evarutil.nf_evar evd''' c) evd''' in let check_types evd = let metas = Evd.meta_list evd in let eqns = List.fold_left (fun acc (mv, b) -> match b with - | Clval (n, (t, (c, TypeNotProcessed)), v) -> (mv, c, EConstr.of_constr t.rebus) :: acc + | Clval (n, (t, (c, TypeNotProcessed)), v) -> (mv, c, t.rebus) :: acc | _ -> acc) [] metas in w_merge_rec evd [] [] eqns in @@ -1417,11 +1416,6 @@ let w_merge env with_types flags (evd,metas,evars : subst0) = in if with_types then check_types res else res -let retract_coercible_metas evd = - let (metas, evd) = retract_coercible_metas evd in - let map (mv, c, st) = (mv, EConstr.of_constr c, st) in - (List.map map metas, evd) - let w_unify_meta_types env ?(flags=default_unify_flags ()) evd = let metas,evd = retract_coercible_metas evd in w_merge env true flags.merge_unify_flags (evd,metas,[]) diff --git a/pretyping/vnorm.ml b/pretyping/vnorm.ml index 3c9b8bc33..049c3aff5 100644 --- a/pretyping/vnorm.ml +++ b/pretyping/vnorm.ml @@ -205,7 +205,7 @@ and nf_univ_args ~nb_univs mk env sigma stk = and nf_evar env sigma evk stk = let evi = try Evd.find sigma evk with Not_found -> assert false in let hyps = Environ.named_context_of_val (Evd.evar_filtered_hyps evi) in - let concl = Evd.evar_concl evi in + let concl = EConstr.Unsafe.to_constr @@ Evd.evar_concl evi in if List.is_empty hyps then nf_stk env sigma (mkEvar (evk, [||])) concl stk else match stk with @@ -381,8 +381,8 @@ let cbv_vm env sigma c t = if Termops.occur_meta sigma c then CErrors.user_err Pp.(str "vm_compute does not support metas."); (** This evar-normalizes terms beforehand *) - let c = EConstr.to_constr sigma c in - let t = EConstr.to_constr sigma t in + let c = EConstr.to_constr ~abort_on_undefined_evars:false sigma c in + let t = EConstr.to_constr ~abort_on_undefined_evars:false sigma t in let v = Vconv.val_of_constr env c in EConstr.of_constr (nf_val env sigma v t) diff --git a/printing/printer.ml b/printing/printer.ml index 199aa79c6..edcce874d 100644 --- a/printing/printer.ml +++ b/printing/printer.ml @@ -93,13 +93,13 @@ let _ = Hook.set Refine.pr_constr pr_constr_env let pr_lconstr_goal_style_env env sigma c = pr_leconstr_core true env sigma (EConstr.of_constr c) let pr_constr_goal_style_env env sigma c = pr_econstr_core true env sigma (EConstr.of_constr c) -let pr_open_lconstr_env env sigma (_,c) = pr_lconstr_env env sigma c -let pr_open_constr_env env sigma (_,c) = pr_constr_env env sigma c - let pr_econstr_n_env env sigma c = pr_econstr_n_core false env sigma c let pr_leconstr_env env sigma c = pr_leconstr_core false env sigma c let pr_econstr_env env sigma c = pr_econstr_core false env sigma c +let pr_open_lconstr_env env sigma (_,c) = pr_leconstr_env env sigma c +let pr_open_constr_env env sigma (_,c) = pr_econstr_env env sigma c + (* NB do not remove the eta-redexes! Global.env() has side-effects... *) let pr_lconstr t = let (sigma, env) = Pfedit.get_current_context () in @@ -108,12 +108,12 @@ let pr_constr t = let (sigma, env) = Pfedit.get_current_context () in pr_constr_env env sigma t -let pr_open_lconstr (_,c) = pr_lconstr c -let pr_open_constr (_,c) = pr_constr c - let pr_leconstr c = pr_lconstr (EConstr.Unsafe.to_constr c) let pr_econstr c = pr_constr (EConstr.Unsafe.to_constr c) +let pr_open_lconstr (_,c) = pr_leconstr c +let pr_open_constr (_,c) = pr_econstr c + let pr_constr_under_binders_env_gen pr env sigma (ids,c) = (* Warning: clashes can occur with variables of same name in env but *) (* we also need to preserve the actual names of the patterns *) @@ -541,12 +541,12 @@ let pr_evgl_sign sigma evi = if List.is_empty ids then mt () else (str " (" ++ prlist_with_sep pr_comma pr_id ids ++ str " cannot be used)") in - let pc = pr_lconstr_env env sigma evi.evar_concl in + let pc = pr_leconstr_env env sigma evi.evar_concl in let candidates = match evi.evar_body, evi.evar_candidates with | Evar_empty, Some l -> spc () ++ str "= {" ++ - prlist_with_sep (fun () -> str "|") (pr_lconstr_env env sigma) l ++ str "}" + prlist_with_sep (fun () -> str "|") (pr_leconstr_env env sigma) l ++ str "}" | _ -> mt () in @@ -622,8 +622,8 @@ let print_evar_constraints gl sigma = end in let pr_evconstr (pbty,env,t1,t2) = - let t1 = Evarutil.nf_evar sigma (EConstr.of_constr t1) - and t2 = Evarutil.nf_evar sigma (EConstr.of_constr t2) in + let t1 = Evarutil.nf_evar sigma t1 + and t2 = Evarutil.nf_evar sigma t2 in let env = (** We currently allow evar instances to refer to anonymous de Bruijn indices, so we protect the error printing code in this case by giving diff --git a/proofs/clenv.ml b/proofs/clenv.ml index 03ff580ad..aeaf16723 100644 --- a/proofs/clenv.ml +++ b/proofs/clenv.ml @@ -62,9 +62,6 @@ let clenv_get_type_of ce c = Retyping.get_type_of (cl_env ce) (cl_sigma ce) c exception NotExtensibleClause -let mk_freelisted c = - map_fl EConstr.of_constr (mk_freelisted (EConstr.Unsafe.to_constr c)) - let clenv_push_prod cl = let typ = whd_all (cl_env cl) (cl_sigma cl) (clenv_type cl) in let rec clrec typ = match EConstr.kind cl.evd typ with @@ -73,7 +70,7 @@ let clenv_push_prod cl = let mv = new_meta () in let dep = not (noccurn (cl_sigma cl) 1 u) in let na' = if dep then na else Anonymous in - let e' = meta_declare mv (EConstr.Unsafe.to_constr t) ~name:na' cl.evd in + let e' = meta_declare mv t ~name:na' cl.evd in let concl = if dep then subst1 (mkMeta mv) u else u in let def = applist (cl.templval.rebus,[mkMeta mv]) in { templval = mk_freelisted def; @@ -107,8 +104,7 @@ let clenv_environments evd bound t = let mv = new_meta () in let dep = not (noccurn evd 1 t2) in let na' = if dep then na else Anonymous in - let t1 = EConstr.Unsafe.to_constr t1 in - let e' = meta_declare mv t1 ~name:na' e in + let e' = meta_declare mv t1 ~name:na' e in clrec (e', (mkMeta mv)::metas) (Option.map ((+) (-1)) n) (if dep then (subst1 (mkMeta mv) t2) else t2) | (n, LetIn (na,b,_,t)) -> clrec (e,metas) n (subst1 b t) @@ -167,13 +163,13 @@ let clenv_assign mv rhs clenv = user_err Pp.(str "clenv_assign: circularity in unification"); try if meta_defined clenv.evd mv then - if not (EConstr.eq_constr clenv.evd (EConstr.of_constr (fst (meta_fvalue clenv.evd mv)).rebus) rhs) then + if not (EConstr.eq_constr clenv.evd (fst (meta_fvalue clenv.evd mv)).rebus rhs) then error_incompatible_inst clenv mv else clenv else let st = (Conv,TypeNotProcessed) in - {clenv with evd = meta_assign mv (EConstr.Unsafe.to_constr rhs_fls.rebus,st) clenv.evd} + {clenv with evd = meta_assign mv (rhs_fls.rebus,st) clenv.evd} with Not_found -> user_err Pp.(str "clenv_assign: undefined meta") @@ -218,7 +214,7 @@ let clenv_assign mv rhs clenv = *) let clenv_metas_in_type_of_meta evd mv = - (mk_freelisted (meta_instance evd (map_fl EConstr.of_constr (meta_ftype evd mv)))).freemetas + (mk_freelisted (meta_instance evd (meta_ftype evd mv))).freemetas let dependent_in_type_of_metas clenv mvs = List.fold_right @@ -288,11 +284,11 @@ let adjust_meta_source evd mv = function in situations like "ex_intro (fun x => P) ?ev p" *) let f = function (mv',(Cltyp (_,t) | Clval (_,_,t))) -> if Metaset.mem mv t.freemetas then - let f,l = decompose_app evd (EConstr.of_constr t.rebus) in + let f,l = decompose_app evd t.rebus in match EConstr.kind evd f with | Meta mv'' -> (match meta_opt_fvalue evd mv'' with - | Some (c,_) -> match_name (EConstr.of_constr c.rebus) l + | Some (c,_) -> match_name c.rebus l | None -> None) | _ -> None else None in @@ -502,7 +498,6 @@ let clenv_assign_binding clenv k c = let k_typ = clenv_hnf_constr clenv (clenv_meta_type clenv k) in let c_typ = nf_betaiota clenv.env clenv.evd (clenv_get_type_of clenv c) in let status,clenv',c = clenv_unify_binding_type clenv c c_typ k_typ in - let c = EConstr.Unsafe.to_constr c in { clenv' with evd = meta_assign k (c,(Conv,status)) clenv'.evd } let clenv_match_args bl clenv = @@ -515,7 +510,7 @@ let clenv_match_args bl clenv = (fun clenv {CAst.loc;v=(b,c)} -> let k = meta_of_binder clenv loc mvs b in if meta_defined clenv.evd k then - if EConstr.eq_constr clenv.evd (EConstr.of_constr (fst (meta_fvalue clenv.evd k)).rebus) c then clenv + if EConstr.eq_constr clenv.evd (fst (meta_fvalue clenv.evd k)).rebus c then clenv else error_already_defined b else clenv_assign_binding clenv k c) @@ -677,7 +672,7 @@ let define_with_type sigma env ev c = let j = Environ.make_judge c ty in let (sigma, j) = Coercion.inh_conv_coerce_to true env sigma j t in let (ev, _) = destEvar sigma ev in - let sigma = Evd.define ev (EConstr.Unsafe.to_constr j.Environ.uj_val) sigma in + let sigma = Evd.define ev j.Environ.uj_val sigma in sigma let solve_evar_clause env sigma hyp_only clause = function diff --git a/proofs/evar_refiner.ml b/proofs/evar_refiner.ml index 0d197c92c..c80f370fd 100644 --- a/proofs/evar_refiner.ml +++ b/proofs/evar_refiner.ml @@ -25,8 +25,6 @@ open Ltac_pretype type glob_constr_ltac_closure = ltac_var_map * glob_constr let depends_on_evar sigma evk _ (pbty,_,t1,t2) = - let t1 = EConstr.of_constr t1 in - let t2 = EConstr.of_constr t2 in try Evar.equal (head_evar sigma t1) evk with NoHeadEvar -> try Evar.equal (head_evar sigma t2) evk @@ -35,12 +33,12 @@ let depends_on_evar sigma evk _ (pbty,_,t1,t2) = let define_and_solve_constraints evk c env evd = if Termops.occur_evar evd evk c then Pretype_errors.error_occur_check env evd evk c; - let evd = define evk (EConstr.Unsafe.to_constr c) evd in + let evd = define evk c evd in let (evd,pbs) = extract_changed_conv_pbs evd (depends_on_evar evd evk) in match List.fold_left (fun p (pbty,env,t1,t2) -> match p with - | Success evd -> Evarconv.evar_conv_x full_transparent_state env evd pbty (EConstr.of_constr t1) (EConstr.of_constr t2) + | Success evd -> Evarconv.evar_conv_x full_transparent_state env evd pbty t1 t2 | UnifFailure _ as x -> x) (Success evd) pbs with @@ -59,7 +57,7 @@ let w_refine (evk,evi) (ltac_var,rawc) sigma = Pretyping.fail_evar = false; Pretyping.expand_evars = true } in try Pretyping.understand_ltac flags - env sigma ltac_var (Pretyping.OfType (EConstr.of_constr evi.evar_concl)) rawc + env sigma ltac_var (Pretyping.OfType evi.evar_concl) rawc with e when CErrors.noncritical e -> let loc = Glob_ops.loc_of_glob_constr rawc in user_err ?loc diff --git a/proofs/goal.ml b/proofs/goal.ml index 6912db364..1440d1636 100644 --- a/proofs/goal.ml +++ b/proofs/goal.ml @@ -48,7 +48,7 @@ module V82 = struct (* Access to ".evar_concl" *) let concl evars gl = let evi = Evd.find evars gl in - EConstr.of_constr evi.Evd.evar_concl + evi.Evd.evar_concl (* Access to ".evar_extra" *) let extra evars gl = @@ -61,7 +61,6 @@ module V82 = struct be shelved. It must not appear as a future_goal, so the future goals are restored to their initial value after the evar is created. *) - let concl = EConstr.Unsafe.to_constr concl in let prev_future_goals = Evd.save_future_goals evars in let evi = { Evd.evar_hyps = hyps; Evd.evar_concl = concl; @@ -86,7 +85,7 @@ module V82 = struct if not (Evarutil.occur_evar_upto sigma evk c) then () else Pretype_errors.error_occur_check Environ.empty_env sigma evk c in - Evd.define evk (EConstr.Unsafe.to_constr c) sigma + Evd.define evk c sigma (* Instantiates a goal with an open term, using name of goal for evk' *) let partial_solution_to sigma evk evk' c = @@ -100,7 +99,9 @@ module V82 = struct let same_goal evars1 gl1 evars2 gl2 = let evi1 = Evd.find evars1 gl1 in let evi2 = Evd.find evars2 gl2 in - Constr.equal evi1.Evd.evar_concl evi2.Evd.evar_concl && + let c1 = EConstr.Unsafe.to_constr evi1.Evd.evar_concl in + let c2 = EConstr.Unsafe.to_constr evi2.Evd.evar_concl in + Constr.equal c1 c2 && Environ.eq_named_context_val evi1.Evd.evar_hyps evi2.Evd.evar_hyps let weak_progress glss gls = diff --git a/proofs/pfedit.ml b/proofs/pfedit.ml index 8725f51cd..abda04ff1 100644 --- a/proofs/pfedit.ml +++ b/proofs/pfedit.ml @@ -233,7 +233,7 @@ let apply_implicit_tactic tac = (); fun env sigma evk -> (Environ.named_context env) -> let tac = Proofview.tclTHEN tac (Proofview.tclEXTEND [] (Proofview.tclZERO (CErrors.UserError (None,Pp.str"Proof is not complete."))) []) in (try - let c = Evarutil.nf_evars_universes sigma evi.evar_concl in + let c = Evarutil.nf_evars_universes sigma (EConstr.Unsafe.to_constr evi.evar_concl) in let c = EConstr.of_constr c in if Evarutil.has_undefined_evars sigma c then raise Exit; let (ans, _, ctx) = diff --git a/proofs/proof_global.ml b/proofs/proof_global.ml index d6c0e3341..fc7c437e6 100644 --- a/proofs/proof_global.ml +++ b/proofs/proof_global.ml @@ -340,7 +340,7 @@ let close_proof ~keep_body_ucst_separate ?feedback_id ~now have existential variables in the initial types of goals, we need to normalise them for the kernel. *) let subst_evar k = - Proof.in_proof proof (fun m -> Evd.existential_opt_value m k) in + Proof.in_proof proof (fun m -> Evd.existential_opt_value0 m k) in let nf = Universes.nf_evars_and_universes_opt_subst subst_evar (UState.subst universes) in let make_body = diff --git a/proofs/refine.ml b/proofs/refine.ml index 909556b1e..5a2d82977 100644 --- a/proofs/refine.ml +++ b/proofs/refine.ml @@ -15,7 +15,7 @@ open Context.Named.Declaration module NamedDecl = Context.Named.Declaration let extract_prefix env info = - let ctx1 = List.rev (Environ.named_context env) in + let ctx1 = List.rev (EConstr.named_context env) in let ctx2 = List.rev (Evd.evar_context info) in let rec share l1 l2 accu = match l1, l2 with | d1 :: l1, d2 :: l2 -> @@ -29,21 +29,21 @@ let typecheck_evar ev env sigma = let info = Evd.find sigma ev in (** Typecheck the hypotheses. *) let type_hyp (sigma, env) decl = - let t = EConstr.of_constr (NamedDecl.get_type decl) in + let t = NamedDecl.get_type decl in let evdref = ref sigma in let _ = Typing.e_sort_of env evdref t in let () = match decl with | LocalAssum _ -> () - | LocalDef (_,body,_) -> Typing.e_check env evdref (EConstr.of_constr body) t + | LocalDef (_,body,_) -> Typing.e_check env evdref body t in - (!evdref, Environ.push_named decl env) + (!evdref, EConstr.push_named decl env) in let (common, changed) = extract_prefix env info in - let env = Environ.reset_with_named_context (Environ.val_of_named_context common) env in + let env = Environ.reset_with_named_context (EConstr.val_of_named_context common) env in let (sigma, env) = List.fold_left type_hyp (sigma, env) changed in (** Typecheck the conclusion *) let evdref = ref sigma in - let _ = Typing.e_sort_of env evdref (EConstr.of_constr (Evd.evar_concl info)) in + let _ = Typing.e_sort_of env evdref (Evd.evar_concl info) in !evdref let typecheck_proof c concl env sigma = @@ -106,7 +106,6 @@ let generic_refine ~typecheck f gl = let evs = Evd.map_filter_future_goals (Proofview.Unsafe.advance sigma) evs in let comb,shelf,given_up,evkmain = Evd.dispatch_future_goals evs in (** Proceed to the refinement *) - let c = EConstr.Unsafe.to_constr c in let sigma = match Proofview.Unsafe.advance sigma self with | None -> (** Nothing to do, the goal has been solved by side-effect *) @@ -124,7 +123,8 @@ let generic_refine ~typecheck f gl = (** Mark goals *) let sigma = CList.fold_left Proofview.Unsafe.mark_as_goal sigma comb in let comb = CList.map (fun x -> Proofview.goal_with_state x state) comb in - let trace () = Pp.(hov 2 (str"simple refine"++spc()++ Hook.get pr_constrv env sigma c)) in + let trace () = Pp.(hov 2 (str"simple refine"++spc()++ + Hook.get pr_constrv env sigma (EConstr.Unsafe.to_constr c))) in Proofview.Trace.name_tactic trace (Proofview.tclUNIT v) >>= fun v -> Proofview.Unsafe.tclSETENV (Environ.reset_context env) <*> Proofview.Unsafe.tclEVARS sigma <*> diff --git a/stm/proofBlockDelimiter.ml b/stm/proofBlockDelimiter.ml index 23f976120..0af766219 100644 --- a/stm/proofBlockDelimiter.ml +++ b/stm/proofBlockDelimiter.ml @@ -41,7 +41,7 @@ let simple_goal sigma g gs = let open Evd in let open Evarutil in let evi = Evd.find sigma g in - Set.is_empty (evars_of_term evi.evar_concl) && + Set.is_empty (evars_of_term (EConstr.Unsafe.to_constr evi.evar_concl)) && Set.is_empty (evars_of_filtered_evar_info (nf_evar_info sigma evi)) && not (List.exists (Proofview.depends_on sigma g) gs) diff --git a/stm/stm.ml b/stm/stm.ml index 30aa9ea06..326b6d1c2 100644 --- a/stm/stm.ml +++ b/stm/stm.ml @@ -1896,7 +1896,7 @@ end = struct (* {{{ *) stm_purify (fun () -> let _,_,_,_,sigma0 = Proof.proof (Proof_global.give_me_the_proof ()) in let g = Evd.find sigma0 r_goal in - let is_ground c = Evarutil.is_ground_term sigma0 (EConstr.of_constr c) in + let is_ground c = Evarutil.is_ground_term sigma0 c in if not ( is_ground Evd.(evar_concl g) && List.for_all (Context.Named.Declaration.for_all is_ground) @@ -1919,7 +1919,6 @@ end = struct (* {{{ *) match Evd.(evar_body (find sigma r_goal)) with | Evd.Evar_empty -> RespNoProgress | Evd.Evar_defined t -> - let t = EConstr.of_constr t in let t = Evarutil.nf_evar sigma t in if Evarutil.is_ground_term sigma t then let t = EConstr.Unsafe.to_constr t in diff --git a/tactics/auto.ml b/tactics/auto.ml index 0c0d9bcfc..15a24fb37 100644 --- a/tactics/auto.ml +++ b/tactics/auto.ml @@ -8,8 +8,6 @@ (* * (see LICENSE file for the text of the license) *) (************************************************************************) -module CVars = Vars - open Pp open Util open Names @@ -82,14 +80,13 @@ let connect_hint_clenv poly (c, _, ctx) clenv gl = if poly then (** Refresh the instance of the hint *) let (subst, ctx) = Universes.fresh_universe_context_set_instance ctx in - let map c = CVars.subst_univs_level_constr subst c in let emap c = Vars.subst_univs_level_constr subst c in let evd = Evd.merge_context_set Evd.univ_flexible evd ctx in (** Only metas are mentioning the old universes. *) let clenv = { templval = Evd.map_fl emap clenv.templval; templtyp = Evd.map_fl emap clenv.templtyp; - evd = Evd.map_metas map evd; + evd = Evd.map_metas emap evd; env = Proofview.Goal.env gl; } in clenv, emap c diff --git a/tactics/class_tactics.ml b/tactics/class_tactics.ml index 0260460e6..b11e36bce 100644 --- a/tactics/class_tactics.ml +++ b/tactics/class_tactics.ml @@ -1030,8 +1030,8 @@ module Intpart = Unionfind.Make(Evar.Set)(Evar.Map) let deps_of_constraints cstrs evm p = List.iter (fun (_, _, x, y) -> - let evx = Evarutil.undefined_evars_of_term evm (EConstr.of_constr x) in - let evy = Evarutil.undefined_evars_of_term evm (EConstr.of_constr y) in + let evx = Evarutil.undefined_evars_of_term evm x in + let evy = Evarutil.undefined_evars_of_term evm y in Intpart.union_set (Evar.Set.union evx evy) p) cstrs @@ -1076,7 +1076,7 @@ let error_unresolvable env comp evd = | Some s -> Evar.Set.mem ev s in let fold ev evi (found, accu) = - let ev_class = class_of_constr evd (EConstr.of_constr evi.evar_concl) in + let ev_class = class_of_constr evd evi.evar_concl in if not (Option.is_empty ev_class) && is_part ev then (* focus on one instance if only one was searched for *) if not found then (true, Some ev) diff --git a/tactics/equality.ml b/tactics/equality.ml index 98f627f21..d7a3e9470 100644 --- a/tactics/equality.ml +++ b/tactics/equality.ml @@ -1108,8 +1108,6 @@ let make_tuple env sigma (rterm,rty) lind = let p = mkLambda (na, a, rty) in let sigma, exist_term = Evd.fresh_global env sigma sigdata.intro in let sigma, sig_term = Evd.fresh_global env sigma sigdata.typ in - let exist_term = EConstr.of_constr exist_term in - let sig_term = EConstr.of_constr sig_term in sigma, (applist(exist_term,[a;p;(mkRel lind);rterm]), applist(sig_term,[a;p])) @@ -1203,7 +1201,6 @@ let sig_clausal_form env sigma sort_of_ty siglen ty dflt = let w_type = unsafe_type_of env !evdref w in if Evarconv.e_cumul env evdref w_type a then let exist_term = Evarutil.evd_comb1 (Evd.fresh_global env) evdref sigdata.intro in - let exist_term = EConstr.of_constr exist_term in applist(exist_term,[a;p_i_minus_1;w;tuple_tail]) else user_err Pp.(str "Cannot solve a unification problem.") @@ -1372,7 +1369,6 @@ let inject_at_positions env sigma l2r (eq,_,(t,t1,t2)) eq_clause posns tac = let sigma, (injbody,resty) = build_injector e_env !evdref t1' (mkVar e) cpath in let injfun = mkNamedLambda e t injbody in let sigma,congr = Evd.fresh_global env sigma eq.congr in - let congr = EConstr.of_constr congr in let pf = applist(congr,[t;resty;injfun;t1;t2]) in let sigma, pf_typ = Typing.type_of env sigma pf in let inj_clause = apply_on_clause (pf,pf_typ) eq_clause in diff --git a/tactics/hints.ml b/tactics/hints.ml index a285d6b93..46d162911 100644 --- a/tactics/hints.ml +++ b/tactics/hints.ml @@ -792,7 +792,7 @@ let make_exact_entry env sigma info poly ?(name=PathAny) (c, cty, ctx) = match EConstr.kind sigma cty with | Prod _ -> failwith "make_exact_entry" | _ -> - let pat = Patternops.pattern_of_constr env sigma (EConstr.to_constr sigma cty) in + let pat = Patternops.pattern_of_constr env sigma (EConstr.to_constr ~abort_on_undefined_evars:false sigma cty) in let hd = try head_pattern_bound pat with BoundPattern -> failwith "make_exact_entry" @@ -814,7 +814,7 @@ let make_apply_entry env sigma (eapply,hnf,verbose) info poly ?(name=PathAny) (c let sigma' = Evd.merge_context_set univ_flexible sigma ctx in let ce = mk_clenv_from_env env sigma' None (c,cty) in let c' = clenv_type (* ~reduce:false *) ce in - let pat = Patternops.pattern_of_constr env ce.evd (EConstr.to_constr sigma c') in + let pat = Patternops.pattern_of_constr env ce.evd (EConstr.to_constr ~abort_on_undefined_evars:false sigma c') in let hd = try head_pattern_bound pat with BoundPattern -> failwith "make_apply_entry" in diff --git a/tactics/inv.ml b/tactics/inv.ml index d76c9a697..412954989 100644 --- a/tactics/inv.ml +++ b/tactics/inv.ml @@ -124,12 +124,10 @@ let make_inv_predicate env evd indf realargs id status concl = in let eq_term = eqdata.Coqlib.eq in let eq = Evarutil.evd_comb1 (Evd.fresh_global env) evd eq_term in - let eq = EConstr.of_constr eq in let eqn = applist (eq,[eqnty;lhs;rhs]) in let eqns = (Anonymous, lift n eqn) :: eqns in let refl_term = eqdata.Coqlib.refl in let refl_term = Evarutil.evd_comb1 (Evd.fresh_global env) evd refl_term in - let refl_term = EConstr.of_constr refl_term in let refl = mkApp (refl_term, [|eqnty; rhs|]) in let _ = Evarutil.evd_comb1 (Typing.type_of env) evd refl in let args = refl :: args in diff --git a/tactics/tacticals.ml b/tactics/tacticals.ml index a97ae8f65..5e81e2d4b 100644 --- a/tactics/tacticals.ml +++ b/tactics/tacticals.ml @@ -263,7 +263,7 @@ let pf_with_evars glsev k gls = tclTHEN (Refiner.tclEVARS evd) (k a) gls let pf_constr_of_global gr k = - pf_with_evars (fun gls -> on_snd EConstr.of_constr (pf_apply Evd.fresh_global gls gr)) k + pf_with_evars (fun gls -> pf_apply Evd.fresh_global gls gr) k (** Tacticals of Ltac defined directly in term of Proofview *) module New = struct @@ -506,7 +506,7 @@ module New = struct let evi = Evd.find sigma evk in match Evd.evar_body evi with | Evd.Evar_empty -> Some (evk,evi) - | Evd.Evar_defined c -> match Constr.kind c with + | Evd.Evar_defined c -> match Constr.kind (EConstr.Unsafe.to_constr c) with | Term.Evar (evk,l) -> is_undefined_up_to_restriction sigma evk | _ -> (* We make the assumption that there is no way to refine an @@ -709,7 +709,7 @@ module New = struct let gl_make_elim ind = begin fun gl -> let gr = Indrec.lookup_eliminator (fst ind) (elimination_sort_of_goal gl) in let (sigma, c) = pf_apply Evd.fresh_global gl gr in - (sigma, EConstr.of_constr c) + (sigma, c) end let gl_make_case_dep (ind, u) = begin fun gl -> @@ -769,7 +769,6 @@ module New = struct Proofview.tclEVARMAP >>= fun sigma -> Proofview.tclENV >>= fun env -> let (sigma, c) = Evd.fresh_global env sigma ref in - let c = EConstr.of_constr c in Proofview.Unsafe.tclEVARS sigma <*> Proofview.tclUNIT c end diff --git a/tactics/tactics.ml b/tactics/tactics.ml index 6561a86c2..aae4bc088 100644 --- a/tactics/tactics.ml +++ b/tactics/tactics.ml @@ -1264,7 +1264,6 @@ let cut c = end let error_uninstantiated_metas t clenv = - let t = EConstr.Unsafe.to_constr t in let na = meta_name clenv.evd (List.hd (Metaset.elements (metavars_of t))) in let id = match na with Name id -> id | _ -> anomaly (Pp.str "unnamed dependent meta.") in user_err (str "Cannot find an instance for " ++ Id.print id ++ str".") @@ -1274,7 +1273,7 @@ let check_unresolved_evars_of_metas sigma clenv = (* Refiner.pose_all_metas_as_evars are resolved *) List.iter (fun (mv,b) -> match b with | Clval (_,(c,_),_) -> - (match Constr.kind c.rebus with + (match Constr.kind (EConstr.Unsafe.to_constr c.rebus) with | Evar (evk,_) when Evd.is_undefined clenv.evd evk && not (Evd.mem sigma evk) -> error_uninstantiated_metas (mkMeta mv) clenv @@ -1451,9 +1450,7 @@ let is_nonrec mind = (Global.lookup_mind (fst mind)).mind_finite == Declarations let find_ind_eliminator ind s gl = let gr = lookup_eliminator ind s in - let evd, c = Tacmach.New.pf_apply Evd.fresh_global gl gr in - let c = EConstr.of_constr c in - evd, c + Tacmach.New.pf_apply Evd.fresh_global gl gr let find_eliminator c gl = let ((ind,u),t) = Tacmach.New.pf_reduce_to_quantified_ind gl (Tacmach.New.pf_unsafe_type_of gl c) in @@ -2618,9 +2615,7 @@ let letin_tac_gen with_eq (id,depdecls,lastlhyp,ccl,c) ty = let eqdata = build_coq_eq_data () in let args = if lr then [t;mkVar id;c] else [t;c;mkVar id]in let (sigma, eq) = Evd.fresh_global env sigma eqdata.eq in - let eq = EConstr.of_constr eq in let (sigma, refl) = Evd.fresh_global env sigma eqdata.refl in - let refl = EConstr.of_constr refl in let eq = applist (eq,args) in let refl = applist (refl, [t;mkVar id]) in let term = mkNamedLetIn id c t (mkLetIn (Name heq, refl, eq, ccl)) in @@ -2674,9 +2669,7 @@ let mkletin_goal env sigma store with_eq dep (id,lastlhyp,ccl,c) ty = let eqdata = build_coq_eq_data () in let args = if lr then [t;mkVar id;c] else [t;c;mkVar id]in let (sigma, eq) = Evd.fresh_global env sigma eqdata.eq in - let eq = EConstr.of_constr eq in let (sigma, refl) = Evd.fresh_global env sigma eqdata.refl in - let refl = EConstr.of_constr refl in let eq = applist (eq,args) in let refl = applist (refl, [t;mkVar id]) in let newenv = insert_before [LocalAssum (heq,eq); decl] lastlhyp env in diff --git a/vernac/class.ml b/vernac/class.ml index 59d933108..f0b01061b 100644 --- a/vernac/class.ml +++ b/vernac/class.ml @@ -181,6 +181,7 @@ let build_id_coercion idf_opt source poly = let sigma, vs = match source with | CL_CONST sp -> Evd.fresh_global env sigma (ConstRef sp) | _ -> error_not_transparent source in + let vs = EConstr.Unsafe.to_constr vs in let c = match constant_opt_value_in env (destConst vs) with | Some c -> c | None -> error_not_transparent source in diff --git a/vernac/classes.ml b/vernac/classes.ml index 76d427add..3c133f317 100644 --- a/vernac/classes.ml +++ b/vernac/classes.ml @@ -293,7 +293,7 @@ let new_instance ?(abstract=false) ?(global=false) ?(refine= !refine_instance) (* Check that the type is free of evars now. *) Pretyping.check_evars env Evd.empty sigma termtype; let termtype = to_constr sigma termtype in - let term = Option.map (to_constr sigma) term in + let term = Option.map (to_constr ~abort_on_undefined_evars:false sigma) term in if not (Evd.has_undefined sigma) && not (Option.is_empty term) then declare_instance_constant k pri global imps ?hook id decl poly sigma (Option.get term) termtype diff --git a/vernac/comDefinition.ml b/vernac/comDefinition.ml index b18a60a1f..9aa61ab46 100644 --- a/vernac/comDefinition.ml +++ b/vernac/comDefinition.ml @@ -88,8 +88,8 @@ let interp_definition pl bl poly red_option c ctypopt = let evd = Evd.minimize_universes evd in (* Substitute evars and universes, and add parameters. Note: in program mode some evars may remain. *) - let ctx = List.map (EConstr.to_rel_decl evd) ctx in - let c = Term.it_mkLambda_or_LetIn (EConstr.to_constr evd c) ctx in + let ctx = List.map Termops.(map_rel_decl (to_constr ~abort_on_undefined_evars:false evd)) ctx in + let c = Term.it_mkLambda_or_LetIn (EConstr.to_constr ~abort_on_undefined_evars:false evd c) ctx in let tyopt = Option.map (fun ty -> Term.it_mkProd_or_LetIn (EConstr.to_constr evd ty) ctx) tyopt in (* Keep only useful universes. *) let uvars_fold uvars c = diff --git a/vernac/comFixpoint.ml b/vernac/comFixpoint.ml index a794c2db0..1466fa243 100644 --- a/vernac/comFixpoint.ml +++ b/vernac/comFixpoint.ml @@ -225,7 +225,8 @@ let interp_recursive ~program_mode ~cofix fixl notations = (* Instantiate evars and check all are resolved *) let sigma = solve_unif_constraints_with_heuristics env_rec sigma in let sigma, _ = nf_evars_and_universes sigma in - let fixdefs = List.map (fun c -> Option.map EConstr.(to_constr sigma) c) fixdefs in + (* XXX: We still have evars here in Program *) + let fixdefs = List.map (fun c -> Option.map EConstr.(to_constr ~abort_on_undefined_evars:false sigma) c) fixdefs in let fixtypes = List.map EConstr.(to_constr sigma) fixtypes in let fixctxs = List.map (fun (_,ctx) -> ctx) fixctxs in diff --git a/vernac/comProgramFixpoint.ml b/vernac/comProgramFixpoint.ml index b95741ca4..745f1df1d 100644 --- a/vernac/comProgramFixpoint.ml +++ b/vernac/comProgramFixpoint.ml @@ -229,7 +229,8 @@ let build_wellfounded (recname,pl,n,bl,arityc,body) poly r measure notation = in (* XXX: Capturing sigma here... bad bad *) let hook = Lemmas.mk_hook (hook sigma) in - let fullcoqc = EConstr.to_constr sigma def in + (* XXX: Grounding non-ground terms here... bad bad *) + let fullcoqc = EConstr.to_constr ~abort_on_undefined_evars:false sigma def in let fullctyp = EConstr.to_constr sigma typ in Obligations.check_evars env sigma; let evars, _, evars_def, evars_typ = @@ -261,9 +262,10 @@ let do_program_recursive local poly fixkind fixl ntns = let collect_evars id def typ imps = (* Generalize by the recursive prototypes *) let def = - EConstr.to_constr evd (Termops.it_mkNamedLambda_or_LetIn (EConstr.of_constr def) rec_sign) + EConstr.to_constr ~abort_on_undefined_evars:false evd (Termops.it_mkNamedLambda_or_LetIn (EConstr.of_constr def) rec_sign) and typ = - EConstr.to_constr evd (Termops.it_mkNamedProd_or_LetIn (EConstr.of_constr typ) rec_sign) + (* Worrying... *) + EConstr.to_constr ~abort_on_undefined_evars:false evd (Termops.it_mkNamedProd_or_LetIn (EConstr.of_constr typ) rec_sign) in let evm = collect_evars_of_term evd def typ in let evars, _, def, typ = diff --git a/vernac/himsg.ml b/vernac/himsg.ml index 698ee4703..acb461cac 100644 --- a/vernac/himsg.ml +++ b/vernac/himsg.ml @@ -75,11 +75,7 @@ let rec contract3' env sigma a b c = function | MetaOccurInBody _ | InstanceNotSameType _ | ProblemBeyondCapabilities | UnifUnivInconsistency _ as x -> contract3 env sigma a b c, x | CannotSolveConstraint ((pb,env',t,u),x) -> - let t = EConstr.of_constr t in - let u = EConstr.of_constr u in let env',t,u = contract2 env' sigma t u in - let t = EConstr.Unsafe.to_constr t in - let u = EConstr.Unsafe.to_constr u in let y,x = contract3' env sigma a b c x in y,CannotSolveConstraint ((pb,env',t,u),x) @@ -322,8 +318,6 @@ let explain_unification_error env sigma p1 p2 = function else [str "universe inconsistency"] | CannotSolveConstraint ((pb,env,t,u),e) -> - let t = EConstr.of_constr t in - let u = EConstr.of_constr u in let env = make_all_name_different env sigma in (strbrk "cannot satisfy constraint " ++ pr_leconstr_env env sigma t ++ str " == " ++ pr_leconstr_env env sigma u) @@ -562,9 +556,9 @@ let rec explain_evar_kind env sigma evk ty = function | Evar_kinds.SubEvar (where,evk') -> let evi = Evd.find sigma evk' in let pc = match evi.evar_body with - | Evar_defined c -> pr_leconstr_env env sigma (EConstr.of_constr c) + | Evar_defined c -> pr_leconstr_env env sigma c | Evar_empty -> assert false in - let ty' = EConstr.of_constr evi.evar_concl in + let ty' = evi.evar_concl in (match where with | Some Evar_kinds.Body -> str "the body of " | Some Evar_kinds.Domain -> str "the domain of " @@ -577,11 +571,11 @@ let rec explain_evar_kind env sigma evk ty = function (pr_leconstr_env env sigma ty') (snd evi.evar_source) let explain_typeclass_resolution env sigma evi k = - match Typeclasses.class_of_constr sigma (EConstr.of_constr evi.evar_concl) with + match Typeclasses.class_of_constr sigma evi.evar_concl with | Some _ -> let env = Evd.evar_filtered_env evi in fnl () ++ str "Could not find an instance for " ++ - pr_lconstr_env env sigma evi.evar_concl ++ + pr_leconstr_env env sigma evi.evar_concl ++ pr_trailing_ne_context_of env sigma | _ -> mt() @@ -590,14 +584,14 @@ let explain_placeholder_kind env sigma c e = | Some (SeveralInstancesFound n) -> strbrk " (several distinct possible type class instances found)" | None -> - match Typeclasses.class_of_constr sigma (EConstr.of_constr c) with + match Typeclasses.class_of_constr sigma c with | Some _ -> strbrk " (no type class instance found)" | _ -> mt () let explain_unsolvable_implicit env sigma evk explain = let evi = Evarutil.nf_evar_info sigma (Evd.find_undefined sigma evk) in let env = Evd.evar_filtered_env evi in - let type_of_hole = pr_lconstr_env env sigma evi.evar_concl in + let type_of_hole = pr_leconstr_env env sigma evi.evar_concl in let pe = pr_trailing_ne_context_of env sigma in strbrk "Cannot infer " ++ explain_evar_kind env sigma evk type_of_hole (snd evi.evar_source) ++ @@ -640,8 +634,7 @@ let explain_refiner_cannot_generalize env sigma ty = pr_leconstr_env env sigma ty ++ str "." let explain_no_occurrence_found env sigma c id = - let c = EConstr.to_constr sigma c in - str "Found no subterm matching " ++ pr_lconstr_env env sigma c ++ + str "Found no subterm matching " ++ pr_leconstr_env env sigma c ++ str " in " ++ (match id with | Some id -> Id.print id @@ -766,7 +759,7 @@ let pr_constraints printenv env sigma evars cstrs = let evs = prlist (fun (ev, evi) -> fnl () ++ pr_existential_key sigma ev ++ - str " : " ++ pr_lconstr_env env' sigma evi.evar_concl ++ fnl ()) l + str " : " ++ pr_leconstr_env env' sigma evi.evar_concl ++ fnl ()) l in h 0 (pe ++ evs ++ pr_evar_constraints sigma cstrs) else diff --git a/vernac/obligations.ml b/vernac/obligations.ml index 064e40b9b..3f2792518 100644 --- a/vernac/obligations.ml +++ b/vernac/obligations.ml @@ -209,8 +209,10 @@ let eterm_obligations env name evm fs ?status t ty = List.fold_right (fun (id, (n, nstr), ev) l -> let hyps = Evd.evar_filtered_context ev in - let hyps = trunc_named_context nc_len hyps in - let evtyp, deps, transp = etype_of_evar l hyps ev.evar_concl in + let hyps = trunc_named_context nc_len hyps in + let hyps = EConstr.Unsafe.to_named_context hyps in + let concl = EConstr.Unsafe.to_constr ev.evar_concl in + let evtyp, deps, transp = etype_of_evar l hyps concl in let evtyp, hyps, chop = match chop_product fs evtyp with | Some t -> t, trunc_named_context fs hyps, fs @@ -356,7 +358,7 @@ let _ = optread = get_shrink_obligations; optwrite = set_shrink_obligations; } -let evar_of_obligation o = make_evar (Global.named_context_val ()) o.obl_type +let evar_of_obligation o = make_evar (Global.named_context_val ()) (EConstr.of_constr o.obl_type) let get_obligation_body expand obl = match obl.obl_body with @@ -813,10 +815,9 @@ let rec string_of_list sep f = function let solve_by_tac name evi t poly ctx = let id = name in - let concl = EConstr.of_constr evi.evar_concl in (* spiwack: the status is dropped. *) let (entry,_,ctx') = Pfedit.build_constant_by_tactic - id ~goal_kind:(goal_kind poly) ctx evi.evar_hyps concl (Tacticals.New.tclCOMPLETE t) in + id ~goal_kind:(goal_kind poly) ctx evi.evar_hyps evi.evar_concl (Tacticals.New.tclCOMPLETE t) in let env = Global.env () in let entry = Safe_typing.inline_private_constants_in_definition_entry env entry in let body, () = Future.force entry.const_entry_body in diff --git a/vernac/vernacentries.ml b/vernac/vernacentries.ml index b44c7cccb..a9d1631ba 100644 --- a/vernac/vernacentries.ml +++ b/vernac/vernacentries.ml @@ -449,7 +449,7 @@ let start_proof_and_print k l hook = let evi = Evarutil.nf_evar_info sigma evi in let env = Evd.evar_filtered_env evi in try - let concl = EConstr.of_constr evi.Evd.evar_concl in + let concl = evi.Evd.evar_concl in if not (Evarutil.is_ground_env sigma env && Evarutil.is_ground_term sigma concl) then raise Exit; |