├── .github └── workflows │ ├── check-links.yml │ ├── deploy-pages.yml │ └── docker-action.yml ├── .gitignore ├── LICENSE ├── LICENSE-docs ├── Makefile ├── README.md ├── _CoqProject ├── coq-tricks.opam ├── meta.yml ├── mlc_config.json └── src ├── ArityDefinition.v ├── Bidirectional.v ├── Check.v ├── CheckEnv.v ├── Coercions.v ├── Constructors.v ├── Context.v ├── Deex.v ├── DefEquality.v ├── DivMod.v ├── Function.v ├── HintLocality.v ├── Instantiate.v ├── IntroPatterns.v ├── Learn.v ├── LtacGallinaApplication.v ├── Macros.v ├── Modules.v ├── NoInit.v ├── NotationModule.v ├── Projections.v ├── RecordFunction.v ├── RelationInstances.v ├── RewNotation.v ├── Search.v ├── Sections.v ├── Sleep.v ├── SmallInversions.v ├── TacticNotationOptionalParams.v ├── TypeParametersAndIndices.v ├── UnshelveInstantiate.v └── Views.v /.github/workflows/check-links.yml: -------------------------------------------------------------------------------- 1 | name: Check links 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - '**' 10 | 11 | jobs: 12 | check-links: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Set up Git repository 16 | uses: actions/checkout@v4 17 | 18 | - name: Check for broken Markdown links 19 | uses: tcort/github-action-markdown-link-check@v1 20 | -------------------------------------------------------------------------------- /.github/workflows/deploy-pages.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - '**' 10 | 11 | jobs: 12 | deploy-pages: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Set up Git repository 16 | uses: actions/checkout@v4 17 | 18 | - name: Copy content to deploy 19 | run: | 20 | mkdir public 21 | sed -i -e 's,(\(src/.*\.v\)),(https://github.com/coq-community/coq-tricks/blob/main/\1),g' README.md 22 | cp README.md public/index.md 23 | echo 'theme: jekyll-theme-cayman' > public/_config.yml 24 | 25 | - name: Deploy to GitHub pages 26 | if: github.event_name == 'push' && github.ref == 'refs/heads/main' 27 | uses: crazy-max/ghaction-github-pages@v4 28 | with: 29 | build_dir: public 30 | target_branch: gh-pages 31 | jekyll: true 32 | env: 33 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 34 | -------------------------------------------------------------------------------- /.github/workflows/docker-action.yml: -------------------------------------------------------------------------------- 1 | # This file was generated from `meta.yml`, please do not edit manually. 2 | # Follow the instructions on https://github.com/coq-community/templates to regenerate. 3 | name: Docker CI 4 | 5 | on: 6 | schedule: 7 | - cron: '0 8 * * TUE' 8 | push: 9 | branches: 10 | - main 11 | pull_request: 12 | branches: 13 | - '**' 14 | 15 | jobs: 16 | build: 17 | # the OS must be GNU/Linux to be able to use the docker-coq-action 18 | runs-on: ubuntu-latest 19 | strategy: 20 | matrix: 21 | coq_version: 22 | - '8.20' 23 | fail-fast: false 24 | steps: 25 | - uses: actions/checkout@v4 26 | - uses: coq-community/docker-coq-action@v1 27 | with: 28 | opam_file: 'coq-tricks.opam' 29 | coq_version: ${{ matrix.coq_version }} 30 | 31 | 32 | # See also: 33 | # https://github.com/coq-community/docker-coq-action#readme 34 | # https://github.com/erikmd/docker-coq-github-action-demo 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.aux 2 | *.glob 3 | *.vo 4 | *.vos 5 | *.vok 6 | *.vio 7 | .lia.cache 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright 2024 Tej Chajed and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /LICENSE-docs: -------------------------------------------------------------------------------- 1 | CC0 1.0 Universal 2 | 3 | Statement of Purpose 4 | 5 | The laws of most jurisdictions throughout the world automatically confer 6 | exclusive Copyright and Related Rights (defined below) upon the creator and 7 | subsequent owner(s) (each and all, an "owner") of an original work of 8 | authorship and/or a database (each, a "Work"). 9 | 10 | Certain owners wish to permanently relinquish those rights to a Work for the 11 | purpose of contributing to a commons of creative, cultural and scientific 12 | works ("Commons") that the public can reliably and without fear of later 13 | claims of infringement build upon, modify, incorporate in other works, reuse 14 | and redistribute as freely as possible in any form whatsoever and for any 15 | purposes, including without limitation commercial purposes. These owners may 16 | contribute to the Commons to promote the ideal of a free culture and the 17 | further production of creative, cultural and scientific works, or to gain 18 | reputation or greater distribution for their Work in part through the use and 19 | efforts of others. 20 | 21 | For these and/or other purposes and motivations, and without any expectation 22 | of additional consideration or compensation, the person associating CC0 with a 23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright 24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work 25 | and publicly distribute the Work under its terms, with knowledge of his or her 26 | Copyright and Related Rights in the Work and the meaning and intended legal 27 | effect of CC0 on those rights. 28 | 29 | 1. Copyright and Related Rights. A Work made available under CC0 may be 30 | protected by copyright and related or neighboring rights ("Copyright and 31 | Related Rights"). Copyright and Related Rights include, but are not limited 32 | to, the following: 33 | 34 | i. the right to reproduce, adapt, distribute, perform, display, communicate, 35 | and translate a Work; 36 | 37 | ii. moral rights retained by the original author(s) and/or performer(s); 38 | 39 | iii. publicity and privacy rights pertaining to a person's image or likeness 40 | depicted in a Work; 41 | 42 | iv. rights protecting against unfair competition in regards to a Work, 43 | subject to the limitations in paragraph 4(a), below; 44 | 45 | v. rights protecting the extraction, dissemination, use and reuse of data in 46 | a Work; 47 | 48 | vi. database rights (such as those arising under Directive 96/9/EC of the 49 | European Parliament and of the Council of 11 March 1996 on the legal 50 | protection of databases, and under any national implementation thereof, 51 | including any amended or successor version of such directive); and 52 | 53 | vii. other similar, equivalent or corresponding rights throughout the world 54 | based on applicable law or treaty, and any national implementations thereof. 55 | 56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of, 57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and 58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright 59 | and Related Rights and associated claims and causes of action, whether now 60 | known or unknown (including existing as well as future claims and causes of 61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum 62 | duration provided by applicable law or treaty (including future time 63 | extensions), (iii) in any current or future medium and for any number of 64 | copies, and (iv) for any purpose whatsoever, including without limitation 65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes 66 | the Waiver for the benefit of each member of the public at large and to the 67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver 68 | shall not be subject to revocation, rescission, cancellation, termination, or 69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work 70 | by the public as contemplated by Affirmer's express Statement of Purpose. 71 | 72 | 3. Public License Fallback. Should any part of the Waiver for any reason be 73 | judged legally invalid or ineffective under applicable law, then the Waiver 74 | shall be preserved to the maximum extent permitted taking into account 75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver 76 | is so judged Affirmer hereby grants to each affected person a royalty-free, 77 | non transferable, non sublicensable, non exclusive, irrevocable and 78 | unconditional license to exercise Affirmer's Copyright and Related Rights in 79 | the Work (i) in all territories worldwide, (ii) for the maximum duration 80 | provided by applicable law or treaty (including future time extensions), (iii) 81 | in any current or future medium and for any number of copies, and (iv) for any 82 | purpose whatsoever, including without limitation commercial, advertising or 83 | promotional purposes (the "License"). The License shall be deemed effective as 84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the 85 | License for any reason be judged legally invalid or ineffective under 86 | applicable law, such partial invalidity or ineffectiveness shall not 87 | invalidate the remainder of the License, and in such case Affirmer hereby 88 | affirms that he or she will not (i) exercise any of his or her remaining 89 | Copyright and Related Rights in the Work or (ii) assert any associated claims 90 | and causes of action with respect to the Work, in either case contrary to 91 | Affirmer's express Statement of Purpose. 92 | 93 | 4. Limitations and Disclaimers. 94 | 95 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 96 | surrendered, licensed or otherwise affected by this document. 97 | 98 | b. Affirmer offers the Work as-is and makes no representations or warranties 99 | of any kind concerning the Work, express, implied, statutory or otherwise, 100 | including without limitation warranties of title, merchantability, fitness 101 | for a particular purpose, non infringement, or the absence of latent or 102 | other defects, accuracy, or the present or absence of errors, whether or not 103 | discoverable, all to the greatest extent permissible under applicable law. 104 | 105 | c. Affirmer disclaims responsibility for clearing rights of other persons 106 | that may apply to the Work or any use thereof, including without limitation 107 | any person's Copyright and Related Rights in the Work. Further, Affirmer 108 | disclaims responsibility for obtaining any necessary consents, permissions 109 | or other rights required for any use of the Work. 110 | 111 | d. Affirmer understands and acknowledges that Creative Commons is not a 112 | party to this document and has no duty or obligation with respect to this 113 | CC0 or use of the Work. 114 | 115 | For more information, please see 116 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | COQ_FILES := $(wildcard src/*.v) 2 | VO_FILES := $(COQ_FILES:.v=.vo) 3 | 4 | # this allows some customization of flags for particular files 5 | COQ_ARGS := 6 | 7 | all: $(VO_FILES) 8 | 9 | src/%.vo: src/%.v 10 | coqc -q -Q src Tricks $(COQ_ARGS) $< -o $@ 11 | 12 | # these rules set COQ_ARGS where needed 13 | src/NoInit.vo: COQ_ARGS = -noinit 14 | src/TacticNotationOptionalParams.vo: COQ_ARGS = -async-proofs-cache force 15 | 16 | clean: 17 | rm -f src/*.vo 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tricks in Coq 2 | 3 | [![Docker CI][docker-action-shield]][docker-action-link] 4 | [![Contributing][contributing-shield]][contributing-link] 5 | [![Code of Conduct][conduct-shield]][conduct-link] 6 | [![Zulip][zulip-shield]][zulip-link] 7 | 8 | [docker-action-shield]: https://github.com/coq-community/coq-tricks/actions/workflows/docker-action.yml/badge.svg?branch=main 9 | [docker-action-link]: https://github.com/coq-community/coq-tricks/actions/workflows/docker-action.yml 10 | 11 | [contributing-shield]: https://img.shields.io/badge/contributions-welcome-%23f7931e.svg 12 | [contributing-link]: https://github.com/coq-community/manifesto/blob/master/CONTRIBUTING.md 13 | 14 | [conduct-shield]: https://img.shields.io/badge/%E2%9D%A4-code%20of%20conduct-%23f15a24.svg 15 | [conduct-link]: https://github.com/coq-community/manifesto/blob/master/CODE_OF_CONDUCT.md 16 | 17 | [zulip-shield]: https://img.shields.io/badge/chat-on%20zulip-%23c1272d.svg 18 | [zulip-link]: https://coq.zulipchat.com/#narrow/stream/237663-coq-community-devs.20.26.20users 19 | 20 | Some tips, tricks, and features in Coq that are hard to discover. 21 | 22 | If you have a trick you've found useful feel free to submit an issue or pull request! 23 | 24 | ## Meta 25 | 26 | - Author(s): 27 | - Tej Chajed (initial) 28 | - Coq-community maintainer(s): 29 | - Tej Chajed ([**@tchajed**](https://github.com/tchajed)) 30 | - License: The code in the repository is licensed under the terms of the [MIT license](https://github.com/coq-community/coq-tricks/blob/main/LICENSE). The documentation (including this README) is licensed under the [CC0 license](https://github.com/coq-community/coq-tricks/blob/main/LICENSE-docs). 31 | - Compatible Coq versions: Coq master 32 | 33 | To build all the examples in `src/`, run `make`. 34 | 35 | ## Ltac 36 | 37 | - The `pattern` tactic generalizes an expression over a variable. For example, `pattern y` transforms a goal of `P x y z` into `(fun y => P x y z) y`. An especially useful way to use this is to pattern match on `eval pattern y in constr:(P x y z)` to extract just the function. 38 | - `lazymatch` is like `match` but without backtracking on failures inside the match action. If you're not using failures for backtracking (this is often the case), then `lazymatch` gets better error messages because an error inside the action becomes the overall error message rather than the uninformative "no match" error message. (The semantics of `match` mean Coq can't do obviously do better - it can't distinguish between a bug in the action and intentionally using the failure to prevent pattern matching.) 39 | - `deex` (see [Deex.v](src/Deex.v)) is a useful tactic for extracting the witness from an `exists` hypothesis while preserving the name of the witness and hypothesis. 40 | - `Ltac t ::= foo.` re-defines the tactic `t` to `foo`. This changes the _binding_, so tactics that refer to `t` will use the new definition. You can use this for a form of extensibility: write `Ltac hook := fail` and then use 41 | ```coq 42 | repeat match goal with 43 | | (* initial cases *) 44 | | _ => hook 45 | | (* other cases *) 46 | end 47 | ``` 48 | in your tactic. Now the user can insert an extra case in your tactic's core loop by overriding `hook`. 49 | - `learn` approach - see [Learn.v](src/Learn.v) for a self-contained example or [Clément's thesis](http://pit-claudel.fr/clement/MSc/#org036d20e) for more details 50 | - `unshelve` tactical, especially useful with an eapply - good example use case is constructing an object by refinement where the obligations end up being your proofs with the values as evars, when you wanted to construct the values by proof 51 | - `unfold "+"` works 52 | - `destruct matches` tactic; see [coq-tactical's SimplMatch.v](https://github.com/tchajed/coq-tactical/blob/master/src/SimplMatch.v) 53 | - using `instantiate` to modify evar environment (thanks to Jonathan Leivent on coq-club) 54 | - `eexists ?[x]` lets one name an existential variable to be able to refer to it later 55 | - strong induction is in the standard library: `Require Import Arith.` and use `induction n as [n IHn] using lt_wf_ind.` 56 | - induction on the length of a list: `Require Import Coq.Arith.Wf_nat.` and `induction xs as [xs IHxs] using (induction_ltof1 _ (@length _)); unfold ltof in IHxs.` 57 | - `debug auto`, `debug eauto`, and `debug trivial` give traces, including failed invocations. `info_auto`, `info_eauto`, and `info_trivial` are less verbose ways to debug which only report what the resulting proof includes 58 | - `constructor` and `econstructor` backtrack over the constructors over an inductive, which lets you do fun things exploring the constructors of an inductive type. See [Constructors.v](src/Constructors.v) for some demonstrations. 59 | - There's a way to destruct and maintain an equality: `destruct_with_eqn x`. 60 | You can also do `destruct x eqn:H` to explicitly name the equality 61 | hypothesis. This is similar to `case_eq x; intros`; I'm not sure what the 62 | practical differences are. 63 | - `rew H in t` notation to use `eq_rect` for a (safe) "type cast". Need to 64 | import `EqNotations` - see [RewNotation.v](src/RewNotation.v) for a working 65 | example. 66 | - `intro`-patterns can be combined in a non-trivial way: `intros [=->%lemma]` -- see [IntroPatterns.v](src/IntroPatterns.v). 67 | - `change` tactic supports patterns (`?var`): e.g. `repeat change (fun x => ?f x) with f` would eta-reduce all the functions (of arbitrary arity) in the goal. 68 | - One way to implement a tactic that sleeps for n seconds is in [Sleep.v](src/Sleep.v). 69 | - Some tactics take an "[occurrence clause](https://coq.inria.fr/doc/V8.19.0/refman/proof-engine/tactics.html#occurrence-clauses)" to select where they apply. The common ones are `in *` and `in H` to apply everywhere and in a specific hypotheses, but there are actually a bunch of forms, for example: 70 | - `in H1, H2` (just `H1` and `H2`) 71 | - `in H1, H2 |- *` (`H1`, `H2`, and the goal) 72 | - `in * |-` (just hypotheses) 73 | - `in |-` (nowhere) 74 | - `in |- *` (just the goal, same as leaving the whole thing off) 75 | - `in * |- *` (everywhere, same as `in *`) 76 | These forms would be especially useful if occurrence clauses were first-class objects; that is, if tactics could take and pass occurrence clauses. Currently user-defined tactics support occurrence clauses via a set of tactic notations. 77 | - Defining tactics (`Tactic Notation`s) that accept multiple optional parameters directly is cumbersome, but it can be done more flexibly using Ltac2. An example can be found in [TacticNotationOptionalParams.v](src/TacticNotationOptionalParams.v). 78 | - You can use notations to shorten repetitive Ltac patterns (much like Haskell's [PatternSynonyms](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/pattern_synonyms.html)). Define a notation with holes (underscores) and use it in an Ltac match, eg `Notation anyplus := (_ + _).` and then 79 | ```coq 80 | match goal with 81 | | |- context[anyplus] => idtac 82 | end 83 | ``` 84 | I would recommend using `Local Notation` so the notation isn't available outside the current file. 85 | - You can make all constructors of an inductive hints with `Hint Constructors`; you can also do this locally in a proof with `eauto using t` where `t` is the name of the inductive. 86 | - The `intuition` tactic has some unexpected behaviors. It takes a tactic to run on each goal, which is `auto with *` by default, using hints from _all hint databases_. `intuition idtac` or `intuition eauto` are both much safer. When using these, note that `intuition eauto; simpl` is parsed as `intuition (eauto; simpl)`, which is unlikely to be what you want; you'll need to instead write `(intuition eauto); simpl`. 87 | - The `Coq.Program.Tactics` library has a number of useful tactics and tactic helpers. Some gems that I like: `add_hypothesis` is like `pose proof` but fails if the fact is already in the context (a lightweight version of the `learn` approach); `destruct_one_ex` implements the tricky code to eliminate an `exists` while retaining names (it's a better version of our `deex`); `on_application` matches any application of `f` by simply handling a large number of arities. 88 | - You can structure your proofs using bullets. You [should use them in the order](https://coq.inria.fr/doc/V8.19.0/refman/proofs/writing-proofs/proof-mode.html#bullets) `-`, `+`, `*` so that Proof General indents them correctly. If you need more bullets you can keep going with `--`, `++`, `**` (although you should rarely need more then three levels of bullets in one proof). 89 | - You can use the `set` tactic to create shorthand names for expressions. These are special `let`-bound variables and show up in the hypotheses as `v := def`. To "unfold" these definitions you can do `subst v` (note the explicit name is required, `subst` will not do this by default). This is a good way to make large goals readable, perhaps while figuring out what lemma to extract. It can also be useful if you need to refer these expressions. 90 | - When you write a function in proof mode (useful when dependent types are involved), you probably want to end the proof with `Defined` instead of `Qed`. The difference is that `Qed` makes the proof term opaque and prevents reduction, while `Defined` will simplify correctly. If you mix computational parts and proof parts (eg, functions which produce sigma types) then you may want to separate the proof into a lemma so that it doesn't get unfolded into a large proof term. 91 | - To make an evar an explicit goal, you can use this trick: `unshelve (instantiate (1:=_))`. The way this work is to instantiate the evar with a fresh evar (created due to the `_`) and then unshelve that evar, making it an explicit goal. See [UnshelveInstantiate.v](src/UnshelveInstantiate.v) for a working example. 92 | - The `enough` tactic behaves like `assert` but puts the goal for the stated fact after the current goal rather than before. 93 | - You can use `context E [x]` to bind a context variable, and then `let e := eval context E [y] in ...` to substitute back into the context. See 94 | [Context.v](src/Context.v) for an example. 95 | - If you have a second-order match (using `@?z x`, which bind `z` to a function) and you want to apply the function, there's a trick involving a seemingly useless match. See [LtacGallinaApplication.v](src/LtacGallinaApplication.v) for an example. 96 | - `auto with foo nocore` with the pseudo-database `nocore` disables the default `core` hint databases and only uses hints from `foo` (and the context). 97 | - If you need to apply a theorem to a hypothesis and then immediately destruct the result, there's a concise way to do it without repetition: `apply thm in H as [x H]`, for example, might be used then `thm` produces an existential for a variable named `x`. 98 | - If you have a hypothesis `H: a = b` and need `f a = f b`, you can use `apply (f_equal f) in H`. (Strictly speaking this is just using the `f_equal` theorem in the standard library, but it's also very much like the inverse direction for the `f_equal` tactic.) 99 | - If you want to both run Ltac and return a `constr`, you can do so by wrapping the side effect in `let _ := match goal with _ => side_effect_tactic end in ...`. See for Jason Gross's much more thorough explanation. 100 | - If you want `lia` to help with non-linear arithmetic involving division or modulo (or the similar `quot` and `rem`), you can do that for simple cases with `Ltac Zify.zify_post_hook ::= Z.div_mod_to_equations.` See [DivMod.v](src/DivMod.v) for an example and the [micromega documentation](https://rocq-prover.org/doc/master/refman/addendum/micromega.html) the full details. 101 | - Coq's `admit` will force you to use `Admitted`. If you want to use Qed, you can instead use `Axiom falso : False. Ltac admit := destruct falso.` This can be useful for debugging Qed errors (say, due to universes) or slow Qeds. 102 | 103 | ## Gallina 104 | 105 | - tactics in terms, eg `ltac:(eauto)` can provide a proof argument 106 | - maximally inserted implicit arguments are implicit even when for identifier alone (eg, `nil` is defined to include the implicit list element type) 107 | - maximally inserted arguments can be defined differently for different numbers of arguments - undocumented but [`eq_refl` provides an example](https://github.com/coq/coq/blob/trunk/theories/Init/Logic.v#L297-298) 108 | - `r.(Field)` syntax: same as `Field r`, but convenient when `Field` is a projection function for the (record) type of `r`. If you use these, you might also want `Set Printing Projections` so Coq re-prints calls to projections with the same syntax. 109 | - `Function` vernacular provides a more advanced way to define recursive functions, which removes the restriction of having a structurally decreasing argument; you just need to specify a well-founded relation or a decreasing measure maps to a nat, then prove all necessary obligations to show this function can terminate. See [manual](https://coq.inria.fr/doc/V8.19.0/refman/using/libraries/funind.html#coq:cmd.Function) and examples in [Function.v](src/Function.v) for more details. 110 | 111 | Three alternatives may be considered as drop-in replacements for `Function`. 112 | 113 | - `Program Fixpoint` may be useful when defining a nested recursive function. See [manual](https://coq.inria.fr/doc/V8.19.0/refman/addendum/program.html#program-fixpoint) and [this StackOverflow post](https://stackoverflow.com/questions/10292421/error-in-defining-ackermann-in-coq). 114 | - [CPDT's way](http://adam.chlipala.net/cpdt/html/Cpdt.GeneralRec.html) of defining general recursive functions with `Fix` combinator. 115 | - [Equations](https://github.com/mattam82/Coq-Equations) is a plugin which extends Coq with new commands for defining recursive functions, and compiles everything down to eliminators for inductive types, equality and accessibility. 116 | 117 | - One can pattern-match on tuples under lambdas: `Definition fst {A B} : (A * B) -> A := fun '(x,_) => x.` 118 | - Records fields can be defined with `:>`, which make that field accessor a coercion. There are three ways to use this (since there are three types of coercion classes). See [Coercions.v](src/Coercions.v) for some concrete examples. 119 | - If the field is an ordinary type, the record can be used as that type (the field will implicitly be accessed). One good use case for this is whenever a record includes another record; this coercion will make the field accessors of the sub-record work for the outer record as well. (This is vaguely similar to [Go embedded structs](https://golang.org/doc/effective_go.html#embedding)) 120 | - If the field has a function type, the record can be called. 121 | - If the field is a sort (eg, `Type`), then the record can be used as a type. 122 | - When a Class field (as opposed to a record) is defined with `:>`, it becomes a hint for typeclass resolution. This is useful when a class includes a "super-class" requirement as a field. For example, `Equivalence` has fields for reflexivity, symmetry, and transitivity. The reflexivity field can be used to generically take an `Equivalence` instance and get a reflexivity instance for free. 123 | - The type classes in RelationClasses are useful but can be repetitive to prove. [RelationInstances.v](src/RelationInstances.v) goes through a few ways of making these more convenient, and why you would want to do so (basically you can make `reflexivity`, `transitivity`, and `symmetry` more powerful). 124 | - The types of inductives can be definitions, as long as they expand to an "arity" (a function type ending in `Prop`, `Set`, or `Type`). See [ArityDefinition.v](src/ArityDefinition.v). 125 | - "Views" are a programming pattern that can be used to perform a case analysis only on "relevant" parts of a datatype given the context of the case analysis. See [Views.v](src/Views.v). 126 | - Record fields that are functions can be written in definition-style syntax with the parameters bound after the record name, eg `{| func x y := x + y; |}` (see [RecordFunction.v](src/RecordFunction.v) for a complete example). 127 | - If you have a coercion `get_function : MyRecord >-> Funclass` you can use `Add Printing Coercion get_function` and then add a notation for `get_function` so your coercion can be parsed as function application but printed using some other syntax (and maybe you want that syntax to be `printing only`). 128 | - You can pass implicit arguments explicitly in a keyword-argument-like style, eg `nil (A:=nat)`. Use `About` to figure out argument names. 129 | - If you do nasty dependent pattern matches or use `inversion` on a goal and it produces equalities of `existT`'s, you may benefit from small inversions, described in this [blog post](http://gallium.inria.fr/blog/a-new-Coq-tactic-for-inversion/). While the small inversion tactic is still not available anywhere I can find, some support is built in to Coq's match return type inference; see [SmallInversions.v](src/SmallInversions.v) for examples of how to use that. 130 | - You can use tactics-in-terms with notations to write function-like definitions that are written in Ltac. For example, you can use this facility to write macros that inspect and transform Gallina terms, producing theorem statements and optionally their proofs automatically. A simple example is given in [DefEquality.v](src/DefEquality.v) of writing a function that produces an equality for unfolding a definition. 131 | - Notations can be dangerous since they by default have global scope and are imported by `Import`, with no way to selectively import. A pattern I now use by default to make notations controllable is to define every notation in a module with a scope; see [NotationModule.v](src/NotationModule.v). 132 | 133 | This pattern has several advantages: 134 | 135 | - notations are only loaded as needed, preventing conflicts when not using the notations 136 | - the notations can be brought into scope everywhere as needed with `Import` and `Local Open Scope`, restoring the convenience of a global notation 137 | - if notations conflict, some of them can always be scoped appropriately 138 | 139 | - Coq has a module system, modeled after ML (eg, the one used in OCaml). You can 140 | see some simple examples of using it in [Modules.v](src/Modules.v). In user 141 | code, I've found module types and module functors to be more trouble than they're worth 90% of the time - the biggest issue is that once something is in a module type, the only way to extend it is with a new module that wraps an existing module, and the only way to use the extension is to instantiate it. At the same time, you can mostly simulate module types with records. 142 | - Coq type class resolution is extremely flexible. There's a hint database called `typeclass_instances` and typeclass resolution is essentially `eauto with typeclass_instances`. Normally you add to this database with commands like `Instance`, but you can add whatever you want to it, including `Hint Extern`s. See [coq-record-update](https://github.com/tchajed/coq-record-update) for a practical example. 143 | - Classes are a bit special compared to any other type. First of all, in `(_ : T x1 x2)` Coq will only trigger type class resolution to fill the hole when `T` is a class. Second, classes get special implicit generalization behavior; specifically, you can write `{T}` and Coq will automatically generalize the _arguments to T_, which you don't even have to write down. See [the manual on implicit generalization](https://rocq-prover.org/doc/master/refman/language/extensions/implicit-arguments.html#implicit-generalization) for more details. Note that you don't have to use `Class` at declaration time to make something a class; you can do it after the fact with `Existing Class T`. 144 | - `Set Printing Projections` is nice in theory if you use records, but it 145 | interacts poorly with classes. See [Projections.v](src/Projections.v). 146 | 147 | ## Other Coq commands 148 | 149 | - `Search` vernacular variants; see [Search.v](src/Search.v) for examples. 150 | - `Search s -Learnt` for a search of local hypotheses excluding Learnt 151 | - `Locate` can search for notation, including partial searches. 152 | - `Optimize Heap` (undocumented) runs GC (specifically [`Gc.compact`](https://ocaml.org/manual/5.2/api/Gc.html#VALcompact)) 153 | - `Optimize Proof` (undocumented) runs several simplifications on the current proof term (see [`Proofview.compact`](https://github.com/coq/coq/blob/9a4ca53a3a021cb16de7706ec79a26e49f54de49/engine/proofview.ml#L40)) 154 | - (in Coq 8.12 and earlier) `Generalizable Variable A` enables implicit generalization; `` Definition id `(x:A) := x `` will implicitly add a parameter `A` before `x`. `Generalizable All Variables` enables implicit generalization for any identifier. Note that this surprisingly allows generalization without a backtick in Instances. [Issue #6030](https://github.com/rocq-prover/rocq/issues/6030) generously requests this behavior be documented, but it should probably require enabling some option. This has been fixed in Coq 8.13; the old behavior requires `Set Instance Generalized Output`. In Coq 8.14 the option has been removed. 155 | - `Check` supports partial terms, printing a type along with a context of evars. A cool example is `Check (id _ _)`, where the first underscore must be a function (along with other constraints on the types involved). 156 | - The above also works with named existentials. For example, `Check ?[x] + ?[y]` works. 157 | - `Unset Intuition Negation Unfolding` will cause `intuition` to stop unfolding `not`. 158 | - Definitions can be normalized (simplified/computed) easily with `Definition bar := Eval compute in foo.` 159 | - `Set Uniform Inductive Parameters` (in Coq v8.9+beta onwards) allows you to omit the uniform parameters to an inductive in the constructors. 160 | - `Lemma` and `Theorem` are synonymous, except that `coqdoc` will not show lemmas. Also synonymous: `Corollary`, `Remark`, and `Fact`. `Definition` is nearly synonymous, except that `Theorem x := def` is not supported (you need to use `Definition`). 161 | - Sections are a powerful way to write a collection of definitions and lemmas that all take the same generic arguments. Here are some tricks for working with sections, which are illustrated in [Sections.v](src/Sections.v): 162 | - Use `Context`, which is strictly more powerful than `Variable` - you can declare multiple dependent parameters and get type inference, and can write `{A}` to make sure a parameter is implicit and maximally inserted. 163 | - Tactics and hints are cleared at the end of a section. This is often annoying but you can take advantage of it by writing one-off tactics like `t` that are specific to the automation of a file, and callers don't see it. Similarly with adding hints to `core` with abandon. 164 | - Use notations and implicit types. Say you have a section that defines lists, and you want another file with a bunch of list theorems. You can start with `Context (A:Type). Notation list := (List.list A). Implicit Types (l:list).` and then in the whole section you basically never need to write type annotations. The notation and implicit type disappears at the end of the section so no worries about leaking it. Furthermore, don't write `Theorem foo : forall l,` but instead write `Theorem foo l :`; you can often also avoid using `intros` with this trick (though be careful about doing induction and ending up with a weak induction hypothesis). 165 | - If you write a general-purpose tactic `t` that solves most goals in a section, it gets annoying to write `Proof. t. Qed.` every time. Instead, define `Notation magic := ltac:(t) (only parsing).` and write `Definition foo l : l = l ++ [] := magic.`. You do unfortunately have to write `Definition`; `Lemma` and `Theorem` do not support `:=` definitions. You don't have to call it `magic` but of course it's more fun that way. Note that this isn't the best plan because you end up with transparent proofs, which isn't great; ideally Coq would just support `Theorem foo :=` syntax for opaque proofs. 166 | - Haskell has an operator `f $ x`, which is the same as `f x` except that its parsed differently: `f $ 1 + 1` means `f (1 + 1)`, avoiding parentheses. You can simulate this in Coq with a notation: `Notation "f $ x" := (f x) (at level 60, right associativity, only parsing).` (from [jwiegley/coq-haskell](https://github.com/jwiegley/coq-haskell/blob/83a5db4b5741745ec9d522543d3616c308dfb542/src/Prelude.v#L15)). 167 | - A useful convention for notations is to have them start with a word and an exclamation mark. This is borrowed from @andres-erbsen, who borrowed it from the Rust macro syntax. An example of using this convention is in [Macros.v](src/Macros.v). There are three big advantages to this approach: first, using it consistently alerts readers that a macro is being used, and second, using names makes it much easier to create many macros compared to inventing ASCII syntax, and third, starting every macro with a keyword makes them much easier to get parsing correctly. 168 | - To declare an axiomatic instance of a typeclass, use `Declare Instance foo : TypeClass`. This better than the pattern of `Axiom` + `Existing Instance`. 169 | - To make Ltac scripts more readable, you can use `Set Default Goal Selector "!".`, which will enforce that every Ltac command (sentence) be applied to exactly one focused goal. You achieve that by using a combination of bullets and braces. As a result, when reading a script you can always see the flow of where multiple goals are generated and solved. 170 | - `Arguments foo _ & _` (in Coq 8.11) adds a _bidirectionality hint_ saying that an application of `foo` should infer a type from its arguments after typing the first argument. See [Bidirectional.v](src/Bidirectional.v) for an example and the [latest Coq documentation](https://rocq-prover.org/doc/master/refman/language/extensions/arguments-command.html#bidirectionality-hints). 171 | - Coq 8.11 introduced compiled interfaces, aka `vos` files (as far as I can tell they are a more principled replacement for `vio` files). Suppose you make a change deep down to `Lib.v` and want to start working on `Proof.v` which imports `Lib.v` through many dependencies. With `vos` files, you can recompile all the _signatures_ that `Proof.v` depends on, skippinng proofs, and keep working. The basic way to use them is to compile `Proof.required_vos`, a special dependency `coqdep` generates that will build everything needed to work on `Proof.v`. Coq natively looks for `vos` files in interactive mode, and uses empty `vos` files to indicate that the file is fully compiled in a `vo` file. 172 | 173 | Note that Coq also has `vok` files; it's possible to check the missing proofs in a `vos` file, but this does not produce a `vo` and so all Coq can do is record that the proofs have been checked. They can also be compiled in parallel within a single file, although I don't know how to do that. Compiling `vok`s lets you fairly confidently check proofs, but to really check everything (particularly universe constraints) you need to build `vo` files from scratch. 174 | 175 | Signature files have one big caveat: if Coq cannot determine the type of a 176 | theorem or the proof ends with `Defined` (and thus might be relevant to later 177 | type-checking), it has to run the proof. It does so _silently_, potentially 178 | eliminating any performance benefit. The main reason this happens is due to 179 | proofs in a section that don't annotate which section variables are used with 180 | `Proof using`. Generally this can be fixed with `Set Default Proof Using 181 | "Type"`, though only on Coq 8.12+. 182 | 183 | - Coq 8.12 has a new feature `Set Printing Parentheses` that prints parentheses as if no notations had an associativity. For example, this will print `(1,2,3)` as `((1,2),3)`. This is much more readable than entirely disabling notations. 184 | - You can use `Export Set` or `#[export] Set` to set options in a way that affects any file directly importing the file (but not transitively importing, the way `Global Set` works). This allows a project to locally set up defaults with an `options.v` file with all of its options, which every file imports. You can use this for basic sanity settings, like `Set Default Proof Using "Type".` and `Set Default Goal Selector "!"` without forcing them on all projects that import your project. 185 | - You can use `all: fail "goals remaining".` to assert that a proof is complete. This is useful when you'll use `Admitted.` but want to document (and check in CI) that the proof is complete other than the `admit.` tactics used. 186 | - You can also use `Fail idtac.` to assert that a proof is complete, which is shorter than the above but more arcane. 187 | - You can use `Fail Fail Qed.` to really assert that a proof is complete, including doing universe checks, but then still be able to `Restart` it. I think this is only useful for illustrating small examples but it's amusing that it works. (The new `Succeed` vernacular in Coq 8.15 is a better replacement, because it preserves error messages on failure.) 188 | - Hints can now be set to global, export, or local. Global (the current default) means the hint applies to any module that transitivity imports this one; export makes the hint visible only if the caller imports this module directly. The behavior will eventually change for hints at the top-level so that they become export instead of global (see ), so this might be worth understanding now. [HintLocality.v](src/HintLocality.v) walks through what the three levels do. 189 | - The [uniform inheritance condition for coercions is 190 | gone](https://github.com/coq/coq/pull/15789) as of March 2022. This condition 191 | required that all the implicit arguments of the target of a coercion could be 192 | inferred from the source, so if the source had extra implicit arguments the 193 | definition could not be a coercion. This is no longer the case - elaboration 194 | will infer the missing arguments. There's still a warning but you can disable 195 | it with `#[warning="-uniform-inheritance"]` on the coercion. 196 | 197 | ## Warnings and options 198 | 199 | - You can use `Set Warnings "-deprecated-syntactic-definition"` to achieve the 200 | same effect as `-w -deprecated-syntactic-definition` from the command line, 201 | but from within a Coq file. As of Coq 8.18 you can also use 202 | `#[warning="-deprecated-syntactic-definition"]` to disable the warning for one command. 203 | 204 | ## Using Coq 205 | 206 | - You can pass `-noinit` to `coqc` or `coqtop` to avoid loading the standard library. 207 | - Ltac is provided as a plugin loaded by the standard library; if you have `-noinit` to load it you need `Declare ML Module "ltac_plugin".` (see [NoInit.v](src/NoInit.v)). 208 | - Numeral notations are only provided by the prelude, even if you issue `Require Import Coq.Init.Datatypes`. 209 | - If you use Coq master, the latest Coq reference manual is built and deployed to automatically. 210 | - At Qed, Coq re-checks the proof term, which can take a while. At the same 211 | time, Qed rarely fails - some reasons why it might include that there's a 212 | universe inconsistency, the coinductive guarded check fails, there's a bug in 213 | an OCaml tactic, or there's an incorrect use of `exact_no_check`. It's not so 214 | easy to disable Qed - in Perennial we do so using this 215 | [disable-qed.sh](https://github.com/mit-pdos/perennial/blob/e15783af0abb0614b50c4166b9bab49f5817032c/etc/disable-qed.sh) 216 | script, which replaces `Qed` with `Unshelve. Fail idtac. Admitted.`. This 217 | still ensures there are no goals, but skips the Qed checking. We only skip Qed 218 | during CI, but run it regularly locally to have a fully consistent build; 219 | another good tradeoff would be to run with Qed checking on a weekly basis but 220 | not on every commit. 221 | -------------------------------------------------------------------------------- /_CoqProject: -------------------------------------------------------------------------------- 1 | -Q src Tricks 2 | -------------------------------------------------------------------------------- /coq-tricks.opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "palmskog@gmail.com" 3 | version: "dev" 4 | 5 | homepage: "https://github.com/coq-community/coq-tricks" 6 | dev-repo: "git+https://github.com/coq-community/coq-tricks.git" 7 | bug-reports: "https://github.com/coq-community/coq-tricks/issues" 8 | license: "MIT" 9 | 10 | synopsis: "Tips, tricks, and features in Coq that are hard to discover" 11 | description: """ 12 | Some tips, tricks, and features in Coq that are hard to discover. 13 | 14 | If you have a trick you've found useful feel free to submit an issue or pull request!""" 15 | 16 | build: [make "-j%{jobs}%"] 17 | depends: [ 18 | "coq" {>= "8.20"} 19 | ] 20 | 21 | tags: [ 22 | "category:Miscellaneous/Coq Use Examples" 23 | "keyword:tricks" 24 | "keyword:tips" 25 | "logpath:Tricks" 26 | ] 27 | authors: [ 28 | "Tej Chajed" 29 | ] 30 | -------------------------------------------------------------------------------- /meta.yml: -------------------------------------------------------------------------------- 1 | --- 2 | fullname: Tricks in Coq 3 | shortname: coq-tricks 4 | organization: coq-community 5 | community: true 6 | action: true 7 | opam_name: coq-tricks 8 | branch: main 9 | 10 | synopsis: >- 11 | Tips, tricks, and features in Coq that are hard to discover 12 | 13 | description: |- 14 | Some tips, tricks, and features in Coq that are hard to discover. 15 | 16 | If you have a trick you've found useful feel free to submit an issue or pull request! 17 | 18 | authors: 19 | - name: Tej Chajed 20 | initial: true 21 | 22 | maintainers: 23 | - name: Tej Chajed 24 | nickname: tchajed 25 | 26 | opam-file-maintainer: palmskog@gmail.com 27 | 28 | opam-file-version: dev 29 | 30 | license: 31 | fullname: The code in the repository is licensed under the terms of the MIT license. The documentation (including this README) is licensed under the CC0 license. 32 | identifier: MIT 33 | 34 | supported_coq_versions: 35 | text: Coq master 36 | opam: '{= "dev"}' 37 | 38 | tested_coq_opam_versions: 39 | - version: 'dev' 40 | 41 | # Tuesday 8am UTC (3am EST) 42 | ci_cron_schedule: '0 8 * * TUE' 43 | 44 | namespace: Tricks 45 | 46 | build: |- 47 | ## Building instructions 48 | 49 | ``` shell 50 | git clone https://github.com/coq-community/coq-tricks 51 | cd coq-tricks 52 | make # or make -j 53 | ``` 54 | 55 | keywords: 56 | - name: tricks 57 | - name: tips 58 | 59 | categories: 60 | - name: Miscellaneous/Coq Use Examples 61 | --- 62 | -------------------------------------------------------------------------------- /mlc_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignorePatterns": [ 3 | { 4 | "pattern": "^https://stackoverflow.com/questions/.*" 5 | }, 6 | { 7 | "pattern": "^https://img.shields.io/badge/.*" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/ArityDefinition.v: -------------------------------------------------------------------------------- 1 | Definition Relation T := T -> T -> Prop. 2 | Inductive nateq : Relation nat := | equal_refl : forall n, nateq n n. 3 | -------------------------------------------------------------------------------- /src/Bidirectional.v: -------------------------------------------------------------------------------- 1 | Require Import List. 2 | Import ListNotations. 3 | 4 | Record vtype := { sz: nat; ty: {l: list Type | length l = sz} }. 5 | Definition ft (vt: vtype) := hd Type (proj1_sig vt.(ty)) -> hd Type (proj1_sig vt.(ty)). 6 | Record func (t: vtype): Type := 7 | mkFunc { f: ft t }. 8 | 9 | (* this bidirectionality hint tells Coq to infer the type of mkFunc from its 10 | environment without typing any of its supplied arguments. *) 11 | Arguments mkFunc &. 12 | 13 | Definition f1: func {| ty:= (exist _ [nat:Type] eq_refl) |} := 14 | {| f := fun n => n + 1 |}. 15 | -------------------------------------------------------------------------------- /src/Check.v: -------------------------------------------------------------------------------- 1 | (* searching for notations *) 2 | Locate "+". 3 | 4 | (* it's possible to search with a single token (if you don't know what the parts 5 | of the notation are) *) 6 | Locate "{". 7 | 8 | (* check shows a context for any evars in its argument *) 9 | Check (id _ _). 10 | 11 | (* it also supports naming them, for a more readable context *) 12 | Check (id _ ?[f]). 13 | Check ?[x] + ?[y]. 14 | -------------------------------------------------------------------------------- /src/CheckEnv.v: -------------------------------------------------------------------------------- 1 | Section S. 2 | Variable A:Type. 3 | (* Variable n:nat. *) 4 | 5 | (* Top-level tactics are checked strictly - they must not have any undefined 6 | symbols. But they can access section variables! *) 7 | Ltac ltac_can_refer_to_section_variables := 8 | match goal with 9 | | [ H: A |- _ ] => 10 | idtac H 11 | end. 12 | 13 | (* with some tactics-in-terms trickery we can check the current (Ltac) 14 | environment *) 15 | 16 | (* this appears useless - doesn't the proof state show the same information? *) 17 | Ltac print_env := 18 | repeat match reverse goal with 19 | | [ H: ?t |- _ ] => 20 | idtac H ":" t; fail 21 | end. 22 | 23 | (* ...except in contexts where there is no interactive proof state *) 24 | Check ltac:(print_env; exact true). 25 | 26 | (* the same tactic applies to evar contexts: *) 27 | Goal True. 28 | evar (e1:nat). 29 | evar (e2:nat). 30 | (* e1 depends on A *) 31 | instantiate (e1:=ltac:(print_env)). 32 | (* e2 depends on A and e1 *) 33 | instantiate (e2:=ltac:(print_env)). 34 | (* Note that this trick actually instantiates the evars; because the tactic 35 | doesn't solve the goal, the evars are replaced by new ones, so you can't do 36 | this trick twice in a script (there's no way to refer to the new evar here 37 | because the goal doesn't contain them), but you can always revert and do 38 | something else. *) 39 | Abort. 40 | End S. 41 | -------------------------------------------------------------------------------- /src/Coercions.v: -------------------------------------------------------------------------------- 1 | (* coercion to nat *) 2 | Record small_number := 3 | { num :> nat; 4 | num_small : num < 3 }. 5 | 6 | Check (fun (n:small_number) => n + 3). 7 | 8 | (* coercion to Funclass *) 9 | Record nat_set := 10 | { is_member :> nat -> bool; 11 | max : nat; 12 | no_higher_members : forall n, n > max -> is_member n = false; }. 13 | 14 | Check (fun (s:nat_set) => s 3). 15 | 16 | (* coercion to Sortclass *) 17 | Record magma := 18 | { A :> Type; 19 | op : A -> A -> A; 20 | op_assoc : forall x y z, op x (op y z) = op (op x y) z; }. 21 | 22 | (* note that m is not a type, but can be used as one *) 23 | Check (fun (m:magma) (x:m) => op m x x). 24 | 25 | (* coercions are printing by default (so the above examples are printed as 26 | written), but we can display the calls to the accessors explicitly *) 27 | Set Printing Coercions. 28 | Check (fun (m:magma) (x:m) => op m x x). 29 | (* [fun (m : magma) (x : A m) => op m x x 30 | : forall m : magma, A m -> A m] *) 31 | -------------------------------------------------------------------------------- /src/Constructors.v: -------------------------------------------------------------------------------- 1 | Inductive foo := 2 | | bar0 3 | | bar1 4 | | bar2. 5 | 6 | Definition ctornum f := 7 | match f with 8 | | bar0 => 1 9 | | bar1 => 2 10 | | bar2 => 3 11 | end. 12 | 13 | (* an illustration of constructor backtracking *) 14 | Goal { f:foo | ctornum f = 3 }. 15 | unshelve eapply exist; [ constructor | match goal with 16 | | |- ?g => idtac g 17 | end; reflexivity ]. 18 | Qed. 19 | 20 | (* same as above, but more directly *) 21 | Definition foo_by_ctornum : {f:foo | ctornum f = 3}. 22 | Proof. 23 | (* the tactic after the ; works only because [constructor] backtracks until 24 | [reflexivity] succeeds. *) 25 | unshelve refine (exist _ _ _); [ constructor | reflexivity]. 26 | Defined. 27 | 28 | Inductive NumIsGood (n:nat) : Prop := 29 | | Good0 (H: n = 0) 30 | | Good3 (H: n = 3) 31 | | Good7 (H: n = 7) 32 | . 33 | 34 | Lemma three_is_good : NumIsGood 3. 35 | Proof. 36 | (* [constructor] on its own would pick [Good0], resulting in an unprovable 37 | goal. Adding [solve [ eauto ]] means the whole tactic backtracks on the choice 38 | of constructor. *) 39 | constructor; solve [ eauto ]. 40 | Qed. 41 | 42 | (* a fun but not very useful thing we can do with constructor backtracking is to 43 | print them out: *) 44 | Ltac constructors t := 45 | let make_constructors := 46 | unshelve eapply exist; 47 | [ econstructor | match goal with 48 | | |- ?x = _ => idtac x 49 | end; fail ] in 50 | let x := constr:(ltac:(try (left; make_constructors); 51 | right; exact tt) : {x:t | x = x} + unit) in 52 | idtac. 53 | 54 | Goal True. 55 | constructors foo. 56 | (* output: 57 | bar0 58 | bar1 59 | bar2 *) 60 | Abort. 61 | -------------------------------------------------------------------------------- /src/Context.v: -------------------------------------------------------------------------------- 1 | Theorem test x : 1 + x = x + 2. 2 | Proof. 3 | match goal with 4 | | [ |- ?P x = ?Q ] => 5 | match Q with 6 | (* this context is a context pattern; it binds a context [E] with a "hole" 7 | where x goes (note that [x] was bound by the above pattern) *) 8 | | context E [x] => 9 | (* this context is a function that substitutes into a context, namely 10 | substituting [y] into the hole in the context E *) 11 | let f := constr:(fun y => ltac:(let t := context E [y] in 12 | exact t)) in 13 | (* f is now [fun y => y + 2], the result of taking x + 2, creating the 14 | context _ + 2, then substituting the context under a new binder *) 15 | change (P x = f x) 16 | end 17 | end. 18 | (* goal becomes 19 | [1 + x = (fun y : nat => y + 2) x] 20 | *) 21 | Abort. 22 | -------------------------------------------------------------------------------- /src/Deex.v: -------------------------------------------------------------------------------- 1 | Ltac deex := 2 | repeat match goal with 3 | | [ H: exists (name:_), _ |- _ ] => 4 | let name' := fresh name in 5 | destruct H as [name' H] 6 | end. 7 | 8 | Theorem example (n:nat) (Hex: exists n, n > 3) : exists n, n > 3. 9 | Proof. 10 | deex. 11 | (* creates a fresh n0 for the witness, and preserves the hypothesis name. *) 12 | exists n0; assumption. 13 | Qed. 14 | -------------------------------------------------------------------------------- /src/DefEquality.v: -------------------------------------------------------------------------------- 1 | (* using a tactic notation rather than an ordinary Ltac function ensures that 2 | the argument is parsed appropriately (in this case it's probably not necessary 3 | but you can for example make the argument a uconstr (an untyped term), a 4 | reference (for passing to unfold), or a tactic *) 5 | Local Tactic Notation "unfolded_eq" constr(pf) := 6 | let x := (eval red in pf) in 7 | exact (eq_refl : (pf = x)). 8 | 9 | Notation unfolded_eq pf := ltac:(unfolded_eq pf) (only parsing). 10 | 11 | Module Example. 12 | Definition foo x y z := x + y + z. 13 | Definition foo_eq := unfolded_eq foo. 14 | Check foo_eq. 15 | (* 16 | foo_eq 17 | : foo = (fun x y z : nat => x + y + z) 18 | *) 19 | End Example. 20 | -------------------------------------------------------------------------------- /src/DivMod.v: -------------------------------------------------------------------------------- 1 | From Coq Require Import ZArith. 2 | From Coq Require Import Lia. 3 | 4 | (* [lia] by default can't handle some non-linear arithmetic lia division and 5 | modulo at all. However, we can change the pre-processing step ([zify]) to at 6 | least make some equations about division and modulo available, which can solve 7 | simple goals involving non-linear arithmetic. *) 8 | 9 | (* see https://coq.github.io/doc/master/refman/addendum/micromega.html for a lot 10 | more details on how to use [zify_post_hook] as well as extend zify in other 11 | ways. *) 12 | 13 | Open Scope Z. 14 | 15 | Lemma mod_bound (n k: Z) : 16 | 0 <= n -> 17 | 0 < k -> 18 | n mod k < k. 19 | Proof. 20 | intros. 21 | Fail lia. 22 | Abort. 23 | 24 | (* [lia] is now more powerful (but potentially slower) *) 25 | Ltac Zify.zify_post_hook ::= Z.div_mod_to_equations. 26 | 27 | Lemma mod_bound (n k: Z) : 28 | 0 <= n -> 29 | 0 < k -> 30 | n mod k < k. 31 | Proof. 32 | intros. 33 | lia. 34 | Qed. 35 | -------------------------------------------------------------------------------- /src/Function.v: -------------------------------------------------------------------------------- 1 | From Coq Require Import PeanoNat Recdef Lia FunctionalExtensionality. 2 | 3 | (** Counting the number of digits in binary representation. *) 4 | 5 | (** Show directly defining this function with Fixpoint is not acceptable. 6 | Error: Cannot guess decreasing argument of fix. *) 7 | Fail Fixpoint attempt_1 (n r : nat) : nat := 8 | match n with 9 | | 0 => r 10 | | _ => attempt_1 (Nat.div2 n) (r + 1) 11 | end. 12 | 13 | (** function with decreasing measure. *) 14 | Function attempt_2 (n r : nat) {measure (fun x => x) n} : nat := 15 | match n with 16 | | 0 => r 17 | | _ => attempt_2 (Nat.div2 n) (r + 1) 18 | end. 19 | Proof. 20 | intros. apply Nat.lt_div2. lia. 21 | Defined. 22 | 23 | Compute attempt_2 1024 0. 24 | 25 | (** function with well-founded relation. *) 26 | Function attempt_3 (n r : nat) {wf lt n} : nat := 27 | match n with 28 | | 0 => r 29 | | _ => attempt_3 (Nat.div2 n) (r + 1) 30 | end. 31 | Proof. 32 | + intros. apply Nat.lt_div2. lia. 33 | + apply Wf_nat.lt_wf. 34 | Defined. 35 | 36 | Goal 37 | attempt_2 8 0 = 4. 38 | Proof. 39 | (** use [xx_equation] to expand the recursive function. *) 40 | rewrite attempt_2_equation; simpl. 41 | rewrite attempt_2_equation; simpl. 42 | rewrite attempt_2_equation; simpl. 43 | rewrite attempt_2_equation; simpl. 44 | rewrite attempt_2_equation; simpl. 45 | reflexivity. 46 | Qed. 47 | 48 | (* note that the two above definitions are really just alternate ways of doing 49 | the same thing ([measure] is just a convenience for leveraging the 50 | well-foundedness of [nat]'s [lt]) *) 51 | Theorem attempts_2_and_3_are_the_same : 52 | attempt_2 = attempt_3. 53 | Proof. 54 | reflexivity. 55 | Qed. 56 | 57 | (** Now we'll redo the above using the standard library's [Fix] combinator, 58 | which provides general well-founded recursion. 59 | 60 | See CPDT's chapter http://adam.chlipala.net/cpdt/html/GeneralRec.html for an 61 | excellent overview, including a better description of how this approach itself 62 | works under the hood. *) 63 | Check Fix. 64 | (* 65 | Fix 66 | : forall (A : Type) (R : A -> A -> Prop), 67 | well_founded R -> 68 | forall P : A -> Type, 69 | (forall x : A, (forall y : A, R y x -> P y) -> P x) -> 70 | forall x : A, P x 71 | 72 | To read this, start at the bottom: we're writing a function of type [forall (x:A), P 73 | x]. The recursion is over [A] and decreases the relation [R], which must be 74 | well-founded (think of [A = nat] and [R = lt] as examples). The body of the 75 | function has the type 76 | 77 | [forall (x:A) (F: forall (y:A), R y x -> P y), P x] 78 | 79 | [x] is simply the argument to the body. The second argument is what I've called 80 | [F] here: think of this as being the function being defined itself, in order to 81 | support recursion. The catch is in its signature: instead of just taking [y:A], 82 | it also takes [R y x]; that is, in order to call [F] recursively, you must pass 83 | a proof that the argument used is smaller than the outer argument [x]. Because 84 | [R] is well-founded, eventually this body must stop calling itself recursively. 85 | *) 86 | 87 | Lemma div2_smaller : forall n n', 88 | n = S n' -> 89 | Nat.div2 n < n. 90 | Proof. 91 | destruct n; intros. 92 | discriminate. 93 | apply Nat.lt_div2; lia. 94 | Qed. 95 | 96 | Definition numdigits (n: nat) : nat. 97 | refine 98 | (Fix Wf_nat.lt_wf (fun _ => nat) 99 | (fun n (numdigits: forall (n':nat), n' < n -> nat) => 100 | (* unfortunately we need to convoy a proof to keep track of the 101 | value of [n] when proving we decrease the argument to [numdigits] *) 102 | match n as n0 return (n = n0 -> nat) with 103 | | 0 => fun _ => 0 104 | | S n' => fun H => 1 + numdigits (Nat.div2 n) _ 105 | end eq_refl) n). 106 | eapply div2_smaller; eauto. 107 | Defined. 108 | 109 | (* We need to provide a wrapper around the standard library's [Fix_eq], which 110 | describes the computational behavior of a [Fix] as being the same as a one-step 111 | unfolding. However, the theorem also requires one to prove the body is unable to 112 | distinguish between [F] arguments that are extensionally equal; this is true of 113 | any Gallina code but can't be proven within Coq once and for all. *) 114 | Theorem numdigits_eq : forall n, 115 | numdigits n = match n with 116 | | 0 => 0 117 | | _ => 1 + numdigits (Nat.div2 n) 118 | end. 119 | Proof. 120 | intros. 121 | match goal with 122 | | [ |- ?lhs = _ ] => 123 | match eval unfold numdigits in lhs with 124 | | Fix ?wf ?P ?F _ => 125 | rewrite (Fix_eq wf P F) 126 | end 127 | end. 128 | destruct n; reflexivity. 129 | 130 | intros. 131 | destruct x; auto. 132 | Qed. 133 | 134 | Example numdigits_5 : numdigits 8 = 4. 135 | Proof. 136 | repeat (rewrite numdigits_eq; cbn [Nat.div2 plus]). 137 | reflexivity. 138 | Qed. 139 | -------------------------------------------------------------------------------- /src/HintLocality.v: -------------------------------------------------------------------------------- 1 | (* Here's how local, global, and export hints work in Coq. 2 | 3 | Very similar principles apply to definitions, but hints are a little special 4 | in that: 5 | (1) you can't name them to retrieve them locally (whereas you can qualify the 6 | module for an un-exported definition and still use it) and (2) it's hard to 7 | determine their scope because you can't name them and figure out where they 8 | are 9 | *) 10 | Module A. 11 | (* gfact will have a global hint proving it, 12 | efact will have an export hint, 13 | and lfact only as a local hint *) 14 | Axioms gfact efact lfact : Prop. 15 | Axiom gfact_true : gfact. 16 | Axiom efact_true : efact. 17 | Axiom lfact_true : lfact. 18 | 19 | Global Hint Resolve gfact_true : core. 20 | #[export] Hint Resolve efact_true : core. 21 | Local Hint Resolve lfact_true : core. 22 | End A. 23 | 24 | Module B. 25 | Import A. 26 | (* here we directly imported both hints, so export vs 27 | global makes no difference, but we don't have the 28 | local one *) 29 | 30 | Goal A.gfact. 31 | Proof. auto. Qed. 32 | 33 | Goal A.efact. 34 | Proof. auto. Qed. 35 | 36 | Goal A.lfact. 37 | Proof. Fail progress auto. Abort. 38 | End B. 39 | 40 | Module C. 41 | Import B. 42 | (* here we only have the global hint from A, not the export one *) 43 | 44 | Goal A.gfact. 45 | Proof. auto. Qed. 46 | 47 | Goal A.efact. 48 | Proof. 49 | (* doesn't work, we need to import A to get the relevant 50 | * hint *) 51 | Fail progress auto. 52 | Abort. 53 | 54 | Goal A.lfact. 55 | Proof. Fail progress auto. Abort. 56 | End C. 57 | -------------------------------------------------------------------------------- /src/Instantiate.v: -------------------------------------------------------------------------------- 1 | (* example thanks to Jonathan Leivent, Dec 2, 2016 email to coq-club 2 | 3 | (subject Re: [Coq-Club] Unification Bug?) 4 | 5 | https://sympa.inria.fr/sympa/arc/coq-club/2016-12/msg00007.html 6 | 7 | *) 8 | Definition foo A B : (A -> B) = (A -> B) := eq_refl. 9 | 10 | Goal { T:Type | T=T }. 11 | refine (exist _ (forall (x:?[T1]), ?[T2]) _). 12 | instantiate (T2:=ltac:(clear x)). (*remove dependency of ?T2 on x*) 13 | apply foo. 14 | 15 | Unshelve. 16 | all: exact nat. 17 | Qed. 18 | -------------------------------------------------------------------------------- /src/IntroPatterns.v: -------------------------------------------------------------------------------- 1 | Require Import Coq.Lists.List. 2 | 3 | Section IntroPatterns. 4 | Variables (A : Type) (xs ys : list A). 5 | 6 | Example ThreeIntroPatternsCombined : 7 | S (length ys) = 1 -> xs ++ ys = xs. 8 | Proof. intros [=->%length_zero_iff_nil]. apply app_nil_r. Qed. 9 | (** Notes: 10 | [=] uses injectivity of constructors to strip of [S]s 11 | [intros [=H%length_zero_iff_nil].] would strip of [S]s, turn 12 | [length ys = 0] into [ys = nil] and move it into the context as [H] 13 | But [->] lets us rewrite the equation right away *) 14 | 15 | Theorem conditional_2 (P Q : Prop) : (P -> Q) -> ~(P /\ ~Q). 16 | Proof. intros p_to_q [q%p_to_q []]; exact q. Qed. 17 | (** Notes: %p_to_q weakens P to Q on the fly and 18 | [] applies the hypothesis of type (~ Q) to the goal *) 19 | 20 | End IntroPatterns. 21 | -------------------------------------------------------------------------------- /src/Learn.v: -------------------------------------------------------------------------------- 1 | (* Forward chaining of applications, to facilitate "saturating" the known facts 2 | without specializing. See Clément's thesis 3 | http://pit-claudel.fr/clement/MSc/#org036d20e for a nicer explanation. *) 4 | Module Learn. 5 | Inductive Learnt {P:Prop} := 6 | | AlreadyLearnt (H:P). 7 | 8 | Local Ltac learn_fact H := 9 | let P := type of H in 10 | lazymatch goal with 11 | (* matching the type of H with the Learnt hypotheses means the 12 | learning fails even when the proposition is known by a different 13 | but unifiable type term *) 14 | | [ Hlearnt: @Learnt P |- _ ] => 15 | fail 0 "already knew" P "through" Hlearnt 16 | | _ => pose proof H; pose proof (AlreadyLearnt H) 17 | end. 18 | 19 | Tactic Notation "learn" constr(H) := learn_fact H. 20 | End Learn. 21 | 22 | Section LearnExample. 23 | Import Learn. 24 | 25 | Parameter P : nat -> Prop. 26 | Parameter Q R : nat -> nat -> Prop. 27 | 28 | Axiom P_Q : forall {x}, P x -> exists y, Q x y. 29 | Axiom Q_R : forall {x y}, P x -> Q x y -> R y x. 30 | 31 | Goal forall x, P x -> exists y, R y x. 32 | Proof. 33 | repeat match goal with 34 | | _ => progress intros 35 | | [ H: _ /\ _ |- _ ] => destruct H 36 | | [ H: exists _, _ |- _ ] => destruct H 37 | | [ H: P _ |- _ ] => learn (P_Q H) 38 | | [ H: P ?x, H': Q ?x _ |- _ ] => learn (Q_R H H') 39 | | [ |- exists _, _ ] => eexists 40 | | _ => eassumption 41 | end. 42 | Qed. 43 | 44 | End LearnExample. 45 | -------------------------------------------------------------------------------- /src/LtacGallinaApplication.v: -------------------------------------------------------------------------------- 1 | (* see https://coq.discourse.group/t/gallina-function-application-in-ltac/316 2 | for the original question and answer *) 3 | 4 | Notation "'subst!' y 'for' x 'in' f" := (match y with x => f end) (at level 10). 5 | 6 | Ltac app_beta f x := 7 | match f with 8 | | (fun y => ?F) => constr:(subst! x for y in F) 9 | end. 10 | 11 | Goal True. 12 | match constr:(let x := 3 in x + 2) with 13 | (* using app_beta on f, which is bound to a function of x *) 14 | | let x : nat := ?y in @?f x => 15 | let body_at_0 := app_beta f 0 in 16 | pose proof (eq_refl : body_at_0 = 0 + 2) 17 | end. 18 | 19 | (* using subst! directly on f, where x is a free variable *) 20 | match constr:(let x := 3 in x + 2) with 21 | | let x : nat := ?y in ?f => 22 | let body_at_0 := constr:(subst! 0 for x in f) in 23 | pose proof (eq_refl : body_at_0 = 0 + 2) 24 | end. 25 | Abort. 26 | -------------------------------------------------------------------------------- /src/Macros.v: -------------------------------------------------------------------------------- 1 | Notation "'Some!' x <- a ; f" := 2 | (match a with 3 | | Some x => f 4 | | _ => None 5 | end) 6 | (right associativity, at level 70, x pattern). 7 | 8 | Notation "'ret!' x" := (Some x) (at level 60). 9 | 10 | Definition opt_map A B (x:option A) (f: A -> B) : option B := 11 | Some! x <- x; ret! f x. 12 | -------------------------------------------------------------------------------- /src/Modules.v: -------------------------------------------------------------------------------- 1 | (* module types are collections of definitions and their types. These are 2 | sometimes called "signatures" and you can think of them as "interfaces" (this 3 | terminology as opposed to module type is more common in OCaml; Coq's module 4 | system is modeled off of OCaml's) *) 5 | 6 | Module Type NatM. 7 | Axiom number:nat. 8 | End NatM. 9 | 10 | (* a module can implement a module type, which means it needs to supply a 11 | definition for all the axioms in the module type. *) 12 | (* somewhat confusingly, module types can include definitions, in which case 13 | modules must contain exactly equivalent definitions. *) 14 | 15 | Module ExampleNat <: NatM. 16 | Definition number := 3. 17 | End ExampleNat. 18 | 19 | Module Type Counter. 20 | Axiom T:Type. 21 | Axiom new : T. 22 | Axiom add: T -> T. 23 | Axiom get: T -> nat. 24 | End Counter. 25 | 26 | (* Note that this module just says [: Counter]. This is called "opaque 27 | ascription" and it means that the only thing callers know about this module is 28 | that it implements Counter. In this case, Counter doesn't expose any theorems, 29 | so callers can't reason about its implementation, but in general it would. 30 | Nonetheless you can use this module to write code. *) 31 | Module SimpleCounter : Counter. 32 | Definition T := nat. 33 | Definition new : T := 0. 34 | Definition add c := 1 + c. 35 | Definition get (x:T) := x. 36 | End SimpleCounter. 37 | 38 | (* Modules can be parameterized, taking other modules of some module type as an argument. *) 39 | (* For unclear reasons this is called a "module functor" (there's some loose 40 | connection to category theory). You still see that terminology in OCaml. *) 41 | Module UseCounter (C:Counter) <: NatM. 42 | (* note that new need C.get because even though a counter might be represented 43 | as a nat (as above), the signature doesn't say anything about that. *) 44 | Definition number := C.get (C.add (C.add C.new)). 45 | End UseCounter. 46 | 47 | (* it's possible to apply a module functor (parametrized module) to concrete 48 | modules, of the appropriate signatures. *) 49 | Module UseSimpleCounter := UseCounter SimpleCounter. 50 | 51 | (* Note that in Coq, with dependent types it's possible to simulate most of the 52 | features of modules with ordinary types. Module types are like record types, 53 | their implementations are like values of the record type, and module functors 54 | are ordinary functions. However, modules do provide some syntactic conveniences 55 | (you can write several definitions more easily), and modules can use opaque 56 | ascription which is a bit "more hidden" than an ordinary opaque definition in 57 | Coq. *) 58 | 59 | (* Module types can also have other modules types as parameters, which we didn't 60 | demonstrate here. *) 61 | -------------------------------------------------------------------------------- /src/NoInit.v: -------------------------------------------------------------------------------- 1 | (* note that this file is intended to demonstrate use of Coq's -noinit (same 2 | as -nois) option, which does not load the standard library. Ltac is loaded by 3 | the standard library's prelude, so with -noinit you'll need to load it 4 | manually. *) 5 | 6 | Declare ML Module "ltac_plugin". 7 | Ltac foo := idtac. 8 | 9 | (* Local Variables: *) 10 | (* coq-prog-args: ("-emacs" "-noinit") *) 11 | (* End: *) 12 | -------------------------------------------------------------------------------- /src/NotationModule.v: -------------------------------------------------------------------------------- 1 | From Coq Require Import List. 2 | 3 | Section Array. 4 | Context (A:Type). 5 | Notation list := (list A). 6 | Implicit Types (l:list) (n:nat) (x:A). 7 | 8 | Fixpoint assign l n x' : list := 9 | match l with 10 | | nil => nil 11 | | x::xs => match n with 12 | | 0 => x'::xs 13 | | S n => x::assign xs n x' 14 | end 15 | end. 16 | 17 | Fixpoint index l n : option A := 18 | match l with 19 | | nil => None 20 | | x::xs => match n with 21 | | 0 => Some x 22 | | S n => index xs n 23 | end 24 | end. 25 | End Array. 26 | 27 | Module ArrayNotations. 28 | Declare Scope array_scope. 29 | Delimit Scope array_scope with array. 30 | Notation "l [ i := v ]" := (assign l i v) (at level 10, left associativity) : array_scope. 31 | Notation "l [ i ]" := (index l i) (at level 11, no associativity) : array_scope. 32 | End ArrayNotations. 33 | 34 | (* to use ArrayNotations: *) 35 | Import ArrayNotations. 36 | Local Open Scope array_scope. (* optional *) 37 | -------------------------------------------------------------------------------- /src/Projections.v: -------------------------------------------------------------------------------- 1 | (** 2 | 3 | [Set Printing Projections] is nice if you have records since it shows the fields 4 | using a nice syntax. However, it interacts poorly with classes. See 5 | https://github.com/coq/coq/issues/9814. 6 | 7 | *) 8 | 9 | Set Printing Projections. 10 | 11 | Module point. 12 | Record t := 13 | mk { x: nat; 14 | y: nat; }. 15 | 16 | Lemma t_eta : forall (p: t), 17 | p = {| x := p.(x); y := p.(y) |}. 18 | Proof. 19 | (* the goal is printed as written above, with projection syntax *) 20 | destruct p; simpl. 21 | reflexivity. 22 | Qed. 23 | 24 | End point. 25 | 26 | Class ToNat T := 27 | { to_nat (x:T) : nat; }. 28 | 29 | Instance unit_to_nat_instance : ToNat unit := 30 | { to_nat _ := 0; }. 31 | 32 | (* [Set Printing Projections] causes this to be printed as a projection, even 33 | though we want the instance to be invisible *) 34 | Check (to_nat tt). 35 | (* 36 | unit_to_nat_instance.(to_nat) tt 37 | : nat 38 | *) 39 | 40 | Unset Printing Projections. 41 | (* this is what we want - just [to_nat tt] *) 42 | Check (to_nat tt). 43 | -------------------------------------------------------------------------------- /src/RecordFunction.v: -------------------------------------------------------------------------------- 1 | Module Nats. 2 | Record natf := 3 | { func : nat -> nat -> nat }. 4 | 5 | Definition addf := 6 | {| func x y := x + y |}. 7 | End Nats. 8 | 9 | Module TypeAnnotation. 10 | Record anyf A B := 11 | { func : A -> A -> B }. 12 | 13 | Definition first A := 14 | {| func (x:A) y := x |}. 15 | End TypeAnnotation. 16 | -------------------------------------------------------------------------------- /src/RelationInstances.v: -------------------------------------------------------------------------------- 1 | Require Import RelationClasses. 2 | (* The classes in RelationClasses are useful to implement. Implementing 3 | [PreOrder] will make the [reflexivity], [transitivity], and [etransitivity] 4 | tactics work with your own relations (much better than manually figuring out 5 | which transitivity lemma to apply!). Here's a nice way to make implementing 6 | relation classes more convenient. *) 7 | 8 | Ltac RelInstance_t := 9 | intros; 10 | let refl := try solve [ hnf; intros; reflexivity ] in 11 | let trans := try solve [ hnf; intros; etransitivity; eauto ] in 12 | try match goal with 13 | | |- Reflexive _ => 14 | hnf; intros; refl 15 | | |- Transitive _ => 16 | hnf; intros; trans 17 | | |- PreOrder _ => 18 | constructor; hnf; intros; [ refl | trans ] 19 | end. 20 | 21 | Definition funext_eq A B (f1 f2: A -> B) := forall x, f1 x = f2 x. 22 | 23 | Section Method1. 24 | (* the most basic way to provide an instance *) 25 | Instance funext_eq_PreOrder1 A B : PreOrder (funext_eq A B). 26 | Proof. 27 | RelInstance_t. 28 | Qed. 29 | End Method1. 30 | 31 | (* we can use tactics-in-terms with notations to create a term-like definition 32 | that is actually a tactic *) 33 | Notation RelInstance := (ltac:(RelInstance_t)) (only parsing). 34 | 35 | Section Method2. 36 | (* this is more powerful than it looks - if [RelInstance] had not solved the 37 | goal, you can prove the remaining goals and finish the instance. *) 38 | Instance funext_eq_PreOrder2 A B : PreOrder (funext_eq A B) := RelInstance. 39 | End Method2. 40 | 41 | Section Method3. 42 | (* Program Instance makes this even more convenient by registering a tactic to 43 | run automatically. It does some of work that [RelInstance_t] is doing, so the 44 | tactic is written to handle Reflexive and Transitive goals in addition to 45 | PreOrder. *) 46 | Obligation Tactic := try RelInstance_t. 47 | Program Instance funext_eq_PreOrder3 A B : PreOrder (funext_eq A B). 48 | End Method3. 49 | 50 | Section Method4. 51 | Instance funext_eq_PreOrder A B : PreOrder (funext_eq A B) := RelInstance. 52 | (* here we re-use an existing instance; this particular case is not very 53 | useful, but if the instance is complicated and combines several existing 54 | instances, these kind of redundant instances like these can speed up typeclass 55 | resolution. *) 56 | Instance funext_eq_PreOrder4 : PreOrder (funext_eq nat nat). 57 | Proof. 58 | typeclasses eauto. 59 | Qed. 60 | End Method4. 61 | -------------------------------------------------------------------------------- /src/RewNotation.v: -------------------------------------------------------------------------------- 1 | Import EqNotations. 2 | 3 | (* just an example context for rewriting *) 4 | Require Fin. 5 | 6 | Definition cast {n m: nat} (H: n = m) 7 | (f: Fin.t n) : Fin.t m := 8 | rew H in f. 9 | 10 | Print cast. (* prints as rew [Fin.t] H in f *) 11 | 12 | Definition cast_is n m (H: n = m) (f: Fin.t n) : 13 | cast H f = eq_rect n Fin.t f m H := eq_refl. 14 | 15 | -------------------------------------------------------------------------------- /src/Search.v: -------------------------------------------------------------------------------- 1 | Require Import Arith. 2 | 3 | (* by default search components are AND'd together, so more components results 4 | in a more specific search *) 5 | Search plus minus. 6 | 7 | (* searching for notations - note that this has to be a token corresponding to 8 | exactly one notation (for more general searches, first find the right pattern 9 | with Locate and then search for that) *) 10 | Search "/" "+". 11 | 12 | (* search patterns can be non-linear (within one component) *) 13 | Search (_ + ?a - ?a). 14 | 15 | Search sumbool (@eq bool _ _). 16 | 17 | Search ({_=_} + {_<>_}). 18 | 19 | (* Note that there is another theorem if this form in ProofIrrelevance (that 20 | works without decidable equality but requires the axiom of proof irrelevance - 21 | the search will not find it if ProofIrrelevance has not been Require'd. *) 22 | Search (existT ?P ?x _ = existT ?P ?x _). 23 | 24 | Search plus inside List. 25 | 26 | (* searches use the name of the theorem if the string is an identifier *) 27 | Search "dec" "<". 28 | 29 | (* mod is part of a notation, but searching for ["mod"] will look for the string 30 | in the lemma name; to search for the notation search for the keyword with 31 | ["'mod'"]. (note that Nat.testbit_eqb, for example, does not have mod in the name) *) 32 | Search "'mod'" 2. 33 | (* the above search would probably be better done like this: *) 34 | Search (_ mod 2). 35 | -------------------------------------------------------------------------------- /src/Sections.v: -------------------------------------------------------------------------------- 1 | Require Import Setoid. 2 | Set Implicit Arguments. 3 | 4 | (** Example of using sections, notations, and implicit types together. *) 5 | 6 | Section Memory. 7 | Context (A V:Type). 8 | Definition mem := A -> option V. 9 | Implicit Types (m:mem) (a:A) (v:V). 10 | 11 | Definition empty : mem := 12 | fun _ => None. 13 | 14 | Definition disjoint m1 m2 := 15 | forall x v, m1 x = Some v -> forall v', m2 x = Some v' -> False. 16 | 17 | Global Instance disjoint_symmetric : Symmetric disjoint. 18 | firstorder. 19 | Qed. 20 | End Memory. 21 | 22 | Section MoreMem. 23 | Context {A V:Type}. 24 | Notation mem := (mem A V). 25 | Implicit Types (m:mem) (a:A) (v:V). 26 | 27 | Context {Aeq: forall (x y:A), {x=y} + {x<>y}}. 28 | 29 | (* this uses the Symmetric instance from above *) 30 | Theorem disjoint_sym m1 m2 : 31 | disjoint m1 m2 <-> disjoint m2 m1. 32 | Proof. 33 | split; symmetry; auto. 34 | Qed. 35 | 36 | Definition upd m a0 v : mem := 37 | fun a => if Aeq a0 a then Some v else m a. 38 | 39 | Theorem upd_eq m a v : upd m a v a = Some v. 40 | Proof. 41 | unfold upd. 42 | destruct (Aeq a a); congruence. 43 | Qed. 44 | 45 | Definition upd_ne m a v a' : 46 | a <> a' -> 47 | upd m a v a' = m a'. 48 | Proof. 49 | unfold upd; intros. 50 | destruct (Aeq a a'); congruence. 51 | Qed. 52 | End MoreMem. 53 | -------------------------------------------------------------------------------- /src/Sleep.v: -------------------------------------------------------------------------------- 1 | Tactic Notation "sleep" integer(seconds) := 2 | do seconds try solve [ timeout 1 (repeat eapply proj1) ]. 3 | 4 | Goal True. 5 | sleep 3. 6 | exact I. 7 | Qed. 8 | -------------------------------------------------------------------------------- /src/SmallInversions.v: -------------------------------------------------------------------------------- 1 | Goal forall T (x y : T), Some x = Some y -> x = y. 2 | Proof. 3 | intros T x y H. 4 | refine match H with eq_refl => eq_refl end. 5 | Qed. 6 | 7 | Goal true <> false. 8 | Proof. 9 | refine (fun H => match H with end). 10 | (* You could also write [refine (fun H => match H with eq_refl => I end).] *) 11 | Qed. 12 | 13 | Goal forall P, true = false -> P. 14 | Proof. 15 | refine (fun P H => match H with end). 16 | Qed. 17 | 18 | Local Set Boolean Equality Schemes. 19 | Inductive foo := a | b | c | d. 20 | 21 | Definition foo_dec_bl x y : foo_beq x y = true -> x = y 22 | := match x, y with 23 | | a, a 24 | | b, b 25 | | c, c 26 | | d, d 27 | => fun _ => eq_refl 28 | | _, _ => fun H : false = true => match H with end 29 | end. 30 | -------------------------------------------------------------------------------- /src/TacticNotationOptionalParams.v: -------------------------------------------------------------------------------- 1 | (** Defining Tactic Notations to take optional parameters is somewhat annoying 2 | currently, as it cannot be done directly with a single command. For example, 3 | Coq's own Classes/SetoidTactics.v defines a "setoid_replace" tactic that 4 | can take any subset of 4 optional parameters. This requires 16 distinct 5 | Tactic Notation commands. 6 | 7 | This can be done in a more flexible matter, using Ltac2 and a trick that 8 | defines the parameters themselves as tactics. It takes some setting up, 9 | so is not necessarily more concise, but it should at least be easier 10 | to add an additional optional parameter. We will reimplement the 11 | "setoid_replace" Tactic Notation to illustrate. 12 | 13 | In short, the idea is as follows: 14 | - Define one Tactic Notation to take a tactic_list (from which we will 15 | extract the proper parameters) 16 | - Define separate Ltac/Tactic Notations for each of your parameters. These will 17 | always throw a special Ltac2 exception that contains the true parameter. 18 | - The outer Tactic Notation will run each of the provided parameter-tactics and 19 | catch their exceptions, using them appropriately.*) 20 | 21 | Set Warnings "-undo-batch-mode". 22 | 23 | From Coq Require Import SetoidTactics. 24 | From Ltac2 Require Import Ltac2 Printf. 25 | (** Next command resets the default tactic language to Ltac.*) 26 | Set Default Proof Mode "Classic". 27 | 28 | (** We start with defining the type of valid parameters for "setoid_replace" *) 29 | Ltac2 Type setoid_replace_param := [ 30 | InClause(Ltac1.t) 31 | | AtClause(Ltac1.t) 32 | | ByClause(Ltac1.t) 33 | | UsingClause(Ltac1.t) 34 | ]. 35 | 36 | (** Now we extend Ltac2's exception type with a constructor designated for 37 | passing on options to "setoid_replace"*) 38 | Ltac2 Type exn ::= [ SetoidReplaceParamExn(setoid_replace_param) ]. 39 | 40 | (** Given an option, we can throw the corresponding exception *) 41 | Ltac2 throw_setoid_replace_param (p : setoid_replace_param) : unit := 42 | Control.zero (SetoidReplaceParamExn p). 43 | 44 | (** To see this in action: *) 45 | Goal True. 46 | Fail ltac2:(throw_setoid_replace_param (InClause ltac1val:(idtac))). 47 | Abort. 48 | 49 | (** Now let us define Tactic Notations for each of the parameters, 50 | starting with "at" *) 51 | 52 | Tactic Notation "at" int_or_var_list(o) := 53 | (** Parsing rules force us to first write the ltac2 closure*) 54 | let f := ltac2:(o' |- 55 | (** Note that ps has type [Ltac1.t], the type of Ltac1 expressions. 56 | There are ways to manipulate these in Ltac2 (like folding over a list, 57 | or matching on optionals) that cannot be done in Ltac1. This can 58 | sometimes be quite useful, and we will make use of that later. *) 59 | throw_setoid_replace_param (AtClause o') 60 | ) in 61 | f o. 62 | 63 | (** We proceed similarly for "in", "by" and "using" *) 64 | 65 | Tactic Notation "in" hyp(id) := 66 | let f := ltac2:(id' |- 67 | throw_setoid_replace_param (InClause id') 68 | ) in 69 | f id. 70 | 71 | (** (Note using by as a parameter-tactic will probably cause conflicts with 72 | existing definitions of "by" in actual developments. This is just an example) *) 73 | Tactic Notation "by" tactic3(t) := 74 | let f := ltac2:(t' |- 75 | throw_setoid_replace_param (ByClause t') 76 | ) in 77 | f t. 78 | 79 | Tactic Notation "using" "relation" constr(rel) := 80 | let f := ltac2:(rel' |- 81 | throw_setoid_replace_param (UsingClause rel') 82 | ) in 83 | f rel. 84 | 85 | Ltac2 Type exn ::= [WrappedExn(message option, exn)]. 86 | (** We now need a way to 'catch' these parameters, given a runnable 87 | 'thunk' that should always throw an appropriate parameter. If it doesn't, 88 | we will raise an error. *) 89 | Ltac2 catch_setoid_replace_param (thunk : unit -> 'a) : setoid_replace_param := 90 | match Control.case thunk with 91 | | Val _ => 92 | let msg := fprintf "No exn was thrown, so the provided parameter is invalid" 93 | (** Note that Control.throw throws an uncatchable exn, ie an error. *) 94 | in Control.throw (Invalid_argument (Some msg)) 95 | | Err e => 96 | match e with 97 | | SetoidReplaceParamExn p => p 98 | | _ => 99 | let msg := fprintf "Bad exn was thrown, so the provided parameter is invalid" 100 | in Control.throw (WrappedExn (Some msg) e) 101 | end 102 | end. 103 | 104 | 105 | (** We now define an Ltac2 wrapper around the four lower level Ltac 106 | "setoidreplace" tactics. This is only necessary in this case, since the 107 | implementation of "setoidreplace" builds on "setoid_rewrite", 108 | whose [in] and [at] parameters are not very flexible. *) 109 | 110 | Ltac2 run_setoid_replace 111 | (** The "in" and "at" parameters, which we use to choose the appropriate variant 112 | of "setoidreplace" *) 113 | (mp_in : Ltac1.t option) 114 | (mp_at : Ltac1.t option) 115 | 116 | (** The "by" and "rel" parameters, for which we have a default value. 117 | "rel" is calculated from the "using" parameter. *) 118 | (p_by : Ltac1.t) 119 | (p_rel : Ltac1.t) : unit := 120 | match mp_in with 121 | | None => 122 | match mp_at with 123 | | None => 124 | ltac1:(H t |- setoidreplace H t) p_rel p_by 125 | | Some p_at => 126 | ltac1:(H t occs |- setoidreplaceat H t occs) p_rel p_by p_at 127 | end 128 | | Some p_in => 129 | match mp_at with 130 | | None => 131 | ltac1:(H H' t |- setoidreplacein H H' t) p_rel p_in p_by 132 | | Some p_at => 133 | ltac1:(H H' t occs |- setoidreplaceinat H H' t occs) p_rel p_in p_by p_at 134 | end 135 | end. 136 | 137 | 138 | (** We now have everything in place to define the outer Tactic Notation. *) 139 | Tactic Notation "setoid_replace_improved" constr(x) "with" constr(y) tactic1_list(ps) := 140 | let f := ltac2:(x_raw y_raw ps_raw |- 141 | (** Start by turning the provided [x_raw : Ltac1.t] into an [x' : constr], 142 | the Ltac2 type of Coq terms. Same for [y_raw]. *) 143 | let x' := Option.get (Ltac1.to_constr x_raw) in 144 | let y' := Option.get (Ltac1.to_constr y_raw) in 145 | (** We set up mutable references to store the final parameter values. 146 | (This can be done without mutable state.) *) 147 | let r_mp_in := { contents := None } in 148 | let r_mp_at := { contents := None } in 149 | (** Default by clause: do nothing, ie run [idtac]*) 150 | let r_p_by := { contents := ltac1val:(idtac) } in 151 | (** Default using clause: use the [default_relation] *) 152 | let r_p_rel := { contents := constr:(default_relation $x' $y') } in 153 | (** Now we first turn the raw tactic list [ps_raw : Ltac1.t] into an Ltac2 [list] of Ltac1 tactics *) 154 | let ps' : Ltac1.t list := Option.get (Ltac1.to_list ps_raw) in 155 | (** We iterate over this list, *) 156 | List.iter (fun p => 157 | (** catch the contained parameter, *) 158 | let param := catch_setoid_replace_param (fun () => Ltac1.run p) in 159 | (** and set our parameter references appropriately *) 160 | match param with 161 | | InClause i => r_mp_in.(contents) := Some i 162 | | AtClause a => r_mp_at.(contents) := Some a 163 | | ByClause t => r_p_by.(contents) := t 164 | | UsingClause r_raw => 165 | let r := Option.get (Ltac1.to_constr r_raw) in 166 | (** We use [x'] and [y'] here to construct the term to rewrite with *) 167 | r_p_rel.(contents) := constr:($r $x' $y') 168 | end 169 | ) ps'; 170 | (** Finally, we read out our parameters and pass them to [run_setoid_replace] *) 171 | run_setoid_replace (r_mp_in.(contents)) (r_mp_at.(contents)) (r_p_by.(contents)) (Ltac1.of_constr (r_p_rel.(contents))) 172 | ) in 173 | f x y ps. 174 | 175 | (** Now let's see this in action. *) 176 | 177 | Require Import Setoid. 178 | 179 | Section test. 180 | Context (A : Set). 181 | Context (eqA : relation A). 182 | Context `{!Equivalence eqA}. 183 | 184 | Context (g : A -> A). 185 | Context (P : A -> A -> Prop). 186 | Context (H_P_proper : Morphisms.Proper (eqA ==> eqA ==> iff) P). 187 | 188 | Lemma test_replace : forall a, P (g a) (g a) -> P (g a) (g a). 189 | Proof. 190 | intros a H. 191 | 192 | (* no options *) 193 | setoid_replace_improved (g a) with (g (g a)). Undo 1. 194 | 195 | (* all 15 other options *) 196 | setoid_replace_improved (g a) with (g (g a)) 197 | in H. Undo 1. 198 | setoid_replace_improved (g a) with (g (g a)) 199 | at 1. Undo 1. 200 | setoid_replace_improved (g a) with (g (g a)) 201 | in H at 1. Undo 1. 202 | setoid_replace_improved (g a) with (g (g a)) 203 | by exfalso. Undo 1. 204 | setoid_replace_improved (g a) with (g (g a)) 205 | in H by exfalso. Undo 1. 206 | setoid_replace_improved (g a) with (g (g a)) 207 | at 1 by exfalso. Undo 1. 208 | setoid_replace_improved (g a) with (g (g a)) 209 | in H at 1 by exfalso. Undo 1. 210 | setoid_replace_improved (g a) with (g (g a)) 211 | using relation (@eq A). Undo 1. 212 | setoid_replace_improved (g a) with (g (g a)) 213 | in H using relation (@eq A). Undo 1. 214 | setoid_replace_improved (g a) with (g (g a)) 215 | at 1 using relation (@eq A). Undo 1. 216 | setoid_replace_improved (g a) with (g (g a)) 217 | in H at 1 using relation (@eq A). Undo 1. 218 | setoid_replace_improved (g a) with (g (g a)) 219 | by exfalso using relation (@eq A). Undo 1. 220 | setoid_replace_improved (g a) with (g (g a)) 221 | in H by exfalso using relation (@eq A). Undo 1. 222 | setoid_replace_improved (g a) with (g (g a)) 223 | at 1 by exfalso using relation (@eq A). Undo 1. 224 | setoid_replace_improved (g a) with (g (g a)) 225 | in H at 1 by exfalso using relation (@eq A). Undo 1. 226 | 227 | (* and the order does not matter! *) 228 | setoid_replace_improved (g a) with (g (g a)) 229 | using relation (@eq A) by exfalso at 1 in H. Undo 1. 230 | 231 | (* one interesting thing with the way we have currently defined it, 232 | is that you can provide multiply provide the same parameters. 233 | Currently, the last one overrides earlier ones, but it is possible to handle this differently *) 234 | setoid_replace_improved (g a) with (g (g a)) at 1 at 2. (* replaces 2, not 1 *) Undo 1. 235 | 236 | (* passing in unappropriate parameters will cause an error *) 237 | Fail setoid_replace_improved (g a) with (g (g a)) at 1 idtac. 238 | Fail setoid_replace_improved (g a) with (g (g a)) at 1 in nonexistent. 239 | 240 | (* Prefixing parameters with tactics is actually allowed*) 241 | setoid_replace_improved (g a) with (g (g a)) (idtac "hello!"; at 1). Undo 1. 242 | 243 | (* using the parameters directly also gives an error. 244 | (One way to improve the readability of this error is to make the constructors of the 245 | [setoid_replace_param] type take an additional string argument, which you set to a 246 | readable error message. *) 247 | Fail at 1. 248 | 249 | (* You can prevent direct usage of parameter-providing tactics by having their names start 250 | with a dash/hyphen: *) 251 | Tactic Notation "-change_at" int_or_var_list(o) := 252 | let f := ltac2:(o' |- 253 | throw_setoid_replace_param (AtClause o') 254 | ) in 255 | f o. 256 | (* this prevents users from writing down: 257 | 258 | -change_at 1. 259 | 260 | directly (try it: it conflicts with structuring proofs into lists of bullet points). 261 | Users can, however, still do: *) 262 | Fail idtac; -change_at 1. 263 | Abort. 264 | End test. 265 | 266 | 267 | 268 | -------------------------------------------------------------------------------- /src/TypeParametersAndIndices.v: -------------------------------------------------------------------------------- 1 | (*** Parameters vs indices *) 2 | 3 | (* Here we explain the difference between parameters (arguments to an inductive 4 | before the colon) and indices (arguments after the colon) with an example. See 5 | https://stackoverflow.com/questions/24600256/difference-between-type-parameters-and-indices 6 | for the original example and a good explanation *) 7 | 8 | (* Parameters make a type "generic" in the sense of polymorphism in other 9 | languages; think lists, which can have elements of different types but look the 10 | same regardless of what the element type is. *) 11 | (* Indices, on the other hand, can affect what inhabitants are in the type. In 12 | other languages inductives with indices are called GADTs. A type can behave 13 | quite differently depending on the index it is passed, and knowing the index of 14 | a type tells you something about its constructors. In Coq the classic example is 15 | [Fin.t n], where [n] determines how many distinct values [Fin.t n] has. *) 16 | 17 | (* Although you can always make everything an index and just happen to use it uniformly over the constructors, the induction principle Coq generates is much better if you make uniform indices parameters instead, as illustrated here. *) 18 | 19 | 20 | (* we use undo intentionally so disable the warning about its efficiency *) 21 | Set Warnings "-undo-batch-mode". 22 | 23 | Module UsingParameter. 24 | Inductive F (T:Type) : nat -> Type := 25 | | C1 : T -> F T 0 26 | | C2 : F T 1 27 | | C3 : F T 0. 28 | Arguments C1 {T} v. 29 | Arguments C2 {T}. 30 | Arguments C3 {T}. 31 | Check F_ind. 32 | (* 33 | F_ind 34 | : forall (T : Type) (P : forall n : nat, F T n -> Prop), 35 | (forall t : T, P 0 (C1 T t)) -> 36 | P 1 (C2 T) -> 37 | P 0 (C3 T) -> 38 | forall (n : nat) (f2 : F T n), P n f2 39 | *) 40 | 41 | Definition getn T (x: F T 0) : nat := 42 | match x with 43 | | C1 _ => 0 44 | | C3 => 3 45 | end. 46 | 47 | Definition f_unit_id n (x:F unit n) : F unit n. 48 | induction x. 49 | exact (C1 t). 50 | exact C2. 51 | exact C3. 52 | Defined. 53 | 54 | Definition f_bool_not n (x:F bool n) : F bool n := 55 | match x with 56 | | C1 b => C1 (negb b) 57 | | C2 => C2 58 | | C3 => C3 59 | end. 60 | End UsingParameter. 61 | 62 | Module UsingUniformIndex. 63 | Inductive F : Type -> nat -> Type := 64 | | C1 : forall T, T -> F T 0 65 | | C2 : forall T, F T 1 66 | | C3 : forall T, F T 0. 67 | Arguments C1 {T} v. 68 | Arguments C2 {T}. 69 | Arguments C3 {T}. 70 | Check F_ind. 71 | (* 72 | F_ind 73 | : forall P : forall (T : Type) (n : nat), F T n -> Prop, 74 | (forall (T : Type) (t : T), P T 0 (C1 T t)) -> 75 | (forall T : Type, P T 1 (C2 T)) -> 76 | (forall T : Type, P T 0 (C3 T)) -> 77 | forall (T : Type) (n : nat) (f2 : F T n), P T n f2 78 | *) 79 | (* note that induction over F T now has a motive that abstracts over T *) 80 | 81 | (* we want to invert the boolean in the C1 constructor *) 82 | Fail Definition f_bool_not n (x:F bool n) : F bool n := 83 | match x with 84 | | C1 b => C1 _ (negb b) 85 | | C2 => C2 86 | | C3 => C3 87 | end. 88 | (* b has type [T] in the first branch when we knew it has type [bool] *) 89 | 90 | (* We can see what goes wrong using tactics (note that this is an 91 | approximation; pattern matches are in general compiled with a different 92 | implementation than the [induction] tactic. However in this case the problem 93 | is that there's no straightforward way to generate this proof; it requires a 94 | type equality since the F recursion principle must be generic over T. *) 95 | Definition f_bool_not n (x:F bool n) : F bool n. 96 | induction x. 97 | (* we've lost any information about the bool parameter to F and 98 | need to do the proof generically over T - the solution was to generalize bool 99 | to T and keep a proof [T = bool], prove something of the form [T = bool -> ...], 100 | and then apply it to the proof [T = bool]. *) 101 | Undo. 102 | remember (bool:Type) as T. 103 | induction x; subst. 104 | exact (C1 (negb t)). 105 | exact C2. 106 | exact C3. 107 | Defined. 108 | 109 | End UsingUniformIndex. 110 | 111 | (* While parameters cannot vary between the type constructed by each of the 112 | constructors, arguments to constructors can use the inductive at different 113 | types. *) 114 | Module VaryingParameterInArguments. 115 | Module Ex1. 116 | Inductive F (T:Type) : Type := 117 | | C1 : F nat -> F T 118 | | C2 : T -> F T. 119 | End Ex1. 120 | 121 | Module Ex2. 122 | Inductive F (T:Type) : Type := 123 | | C1 : (T -> F nat) -> F T 124 | | C2 : T -> F T. 125 | End Ex2. 126 | 127 | Module Ex3. 128 | Fail Inductive F (T:Type) : Type := 129 | (* this is a non-positive occurrence of F, which is never allowed because 130 | it can be used to create proofs of False and thus breaks soundness of Coq 131 | as a logic *) 132 | | C1 : (F T -> nat) -> F T 133 | | C2 : T -> F T. 134 | End Ex3. 135 | End VaryingParameterInArguments. 136 | -------------------------------------------------------------------------------- /src/UnshelveInstantiate.v: -------------------------------------------------------------------------------- 1 | (* see comment on answer https://stackoverflow.com/a/53549978/4084567 *) 2 | 3 | Section Example. 4 | Context (A:Type). 5 | Parameter P Q: A -> Prop. 6 | Definition filter {a} : P a -> A := fun Pa => a. 7 | 8 | Lemma my_lemma: 9 | forall a b, Q b -> (Q b -> P a) -> 10 | exists a (H: P a), P (filter H). 11 | Proof. 12 | intros ?? H H0. 13 | do 2 eexists. 14 | unshelve instantiate (1 := _). 15 | eauto. 16 | auto. 17 | Qed. 18 | End Example. 19 | -------------------------------------------------------------------------------- /src/Views.v: -------------------------------------------------------------------------------- 1 | (** The first part of this file gives some definitions to make the case for an example of views. *) 2 | (** The last parts of the file demonstrate why a view may be useful. *) 3 | 4 | (** For more details, see the mathcomp book, section 5.1 on "Reflection Views" https://zenodo.org/record/7118596 *) 5 | (** The following is another real-world example that defines a view on a list such that the list is reversed: 6 | https://github.com/math-comp/math-comp/blob/7d5618d936496d1f99a76abeb9c636dd3ddaf293/mathcomp/ssreflect/seq.v#L360-L364 *) 7 | Require Import String. 8 | 9 | Inductive expr : Type := 10 | | Value : nat -> expr 11 | | Var : string -> expr 12 | | Plus : expr -> expr -> expr 13 | | Let : string -> expr -> expr -> expr 14 | . 15 | Inductive ectx : Type := 16 | | Ehole : ectx 17 | | EplusR : nat -> ectx -> ectx 18 | | EplusL : ectx -> expr -> ectx 19 | | Elet : string -> ectx -> expr -> ectx 20 | . 21 | (** This function determines the evaluation context of an expression. *) 22 | Fixpoint find_ectx (e : expr) : option(ectx * expr) := 23 | match e with 24 | | Plus e0 e1 => 25 | match e0, e1 with 26 | | Value n0, Value n1 => Some(Ehole, Plus (Value n0) (Value n1)) 27 | | Value n0, _ => 28 | match find_ectx e1 with 29 | | Some(E, e1') => Some(EplusR n0 E, e1') 30 | | None => None 31 | end 32 | | _, _ => 33 | match find_ectx e0 with 34 | | Some(E, e0') => Some(EplusL E e1, e0') 35 | | None => None 36 | end 37 | end 38 | | Let x e0 e1 => 39 | match e0 with 40 | | Value n0 => Some(Ehole, Let x (Value n0) e1) 41 | | _ => 42 | match find_ectx e0 with 43 | | Some(E, e0') => Some(Elet x E e1, e0') 44 | | None => None 45 | end 46 | end 47 | | _ => None 48 | end 49 | . 50 | (** The following lemma shows when and why you'd want to use views. *) 51 | Lemma same e e' : 52 | find_ectx e = Some(Ehole, e') -> 53 | e = e' 54 | . 55 | Proof. 56 | intros; destruct e; try (now inversion H); cbn in H. 57 | - (* e1 is either a value or any other expression *) 58 | destruct e1. 59 | (* this generated 4 subgoals, one of them concerned with a value, 60 | one spurious case, and n=2 exactly similar goals. 61 | n gets larger the more expressions exist and 62 | all these n goals have exactly the same proof *) 63 | (* again, e2 is either a value or any other expression, thereby we 64 | get to n * n goals with exactly similar proofs *) 65 | Abort. 66 | 67 | (** * Views *) 68 | (* Views allow us to focus the case analysis on just the relevant parts, 69 | "combining" all the similar goals to just one. *) 70 | Inductive expr_view : expr -> Type := 71 | | expr_view_value : forall n, expr_view (Value n) 72 | | expr_view_expr : forall e, (forall n, e <> Value n) -> expr_view e 73 | . 74 | #[local] 75 | Hint Constructors expr_view : core. 76 | 77 | (** The following can be used to construct a view from an arbitrary expression. *) 78 | Lemma e_view e : expr_view e. 79 | Proof. destruct e; try econstructor; congruence. Qed. 80 | 81 | Lemma same e e' : 82 | find_ectx e = Some(Ehole, e') -> 83 | e = e' 84 | . 85 | Proof. 86 | intros; destruct e; try (now inversion H); cbn in H. 87 | - (* e1 is either a value or any other expression. By destructing the view, 88 | this information gets reflected now: Only two goals are generated, 89 | instead of four goals *) 90 | destruct (e_view e1). 91 | (* That's basically the trick. *) 92 | Abort. 93 | --------------------------------------------------------------------------------