I am considering writing tactics which will look at multiple goals and make decision based on that. However, when I use match goal with and stare at a goal, how do I say "please find another goal that looks like this"?
Or rather, a more general question is, how can I switch between goals in Ltac?
As we discussed in the comments, it is the case that achieving this kind of inspection of the current proof goal is currently not possible in Ltac.
However, it may be possible to program such a tactic on the ocaml level or in one of the newer tactic languages like ltac2 or mtac.
Related
There is a programming "style" (or maybe paradigm, i'm not sure what to call it) which is as follows:
First, you write a specification: a formal description of what your (whole, or part of) program is to do. This is done within the programming system; it is not a separate artifact.
Then, you write the program, but - and this is the key distinction between this programming style and others - every step of this writing task is guided in some way by the specification you've written in the previous step. How exactly this guidance happens varies wildly; in Coq you have a metaprogramming language (Ltac) which lets you "refine" the specification while building the actual program behind the scenes, whereas in Agda you compose a program by filling "holes" (i'm not actually sure how it goes in Agda, as i'm mostly used to Coq).
This isn't exactly everyone's favorite style of programming, but i'd like to try practicing it in general-purpose, popular programming languages. At least in Coq i've found it to be fairly addictive!
...but how would i even search for ways to do it outside proof assistants? Which leads us to the question: I'm looking for a name for this programming style, so that i can try looking up tools that let me program like that in other programming languages.
Mind you, of course a more proper question would be directly asking for examples of such tools, but AFAIK questions asking for lists of answers aren't appropriate for Stack Exchange sites.
And to be clear, i'm not all that hopeful i'm really going to find much; these are mostly academic pastimes, and your typical programming language isn't really amenable to this style of programming (for example, the specification language might end up being impossibly complex). But it's worth a shot!
It is called proof-driven development (or type-driven development). However, there is very little information about it.
This process you mention about slowly creating your program by means of ltac (in the case of coq) or holes (in the case of Agda and Idris) is called refinement. So you will also find reference in the literature for this style as proof by refinement or programming by refinement.
Now the most important thing to realize is that this style of programming is intrinsic to more complex type system that will allow you to extract as much information as possible the current environment. So it is natural to find attached with dependent types, although it is not necessarily the case.
As mentioned in another response you're also going to find references to it as Type-Driven Development, there is an idris book about it.
You may be interested in looking into some other projects such as Lean, Isabelle, Idris, Agda, Cedille, and maybe Liquid Haskell, TLA+ and SAW.
As pointed out by the two previous answers, a possible name for the program style you mention certainly is: type-driven development.
From the Coq viewpoint, you might be interested in the following two references:
Certified Programming with Dependent Types (CPDT, by Adam Chlipala): a Coq textbook that teaches advanced techniques to develop dependently-typed Coq theories and automate related proofs.
Experience Report: Type-Driven Development of Certified Tree Algorithms in Coq (by Reynald Affeldt, Jacques Garrigue, Xuanrui Qi, Kazunari Tanaka), published at the Coq Workshop 2019 (slides, extended abstract):
The authors also use the acronym TDD, which interestingly enough, also has another acceptation in the software engineering community: test-driven development (this widely used methodology naturally leads to high-quality test suites).
Actually, both acceptations of TDD share a common idea: one systematically starts by writing the specification (of the considered unit), then only after that, writing some code that fulfills the spec (make the unit tests pass), then we loop and incrementally specify+implement(+refactor) other code units.
Last but not least, there are some extra pointers in this discussion from the Discourse OCaml forum.
I'm quite new to coq proof assistant and am still finding my feet.
I've encountered a case which I don't know how to deal with: I tried to use Program Fixpoint tactic to weaken the requirements on my code to later prove the needed properties afterwards as so called Obligations. While most of them were easy, there were two obligations generated goals of which had form [a-quite-simplee-xpr] = [my-function-name]_obligation_3, generally speaking the goals were refering to other obligations which were proved before. I tried unfolding and do substitutions but it didn't really help.
If there's no general solution for such problems I can send the proof script + the screenshot of the obligation to add some context.
Thank you in advance.
One thing that might be happening is that you have types which contain both "data" and "proof" (typically if you're trying to make refinement types with sig, or a custom inductive Type which contains proof terms), and that your functions require proofs of propositional equality, which is generally too strong for such dependent types.
Proof terms should be irrelevant: the simplest way out is to resolve that goal using an axiom from ProofIrrelevance (in the stdlib).
There are axiom-free ways, but I believe they require much more work/expertise.
Let's say I have several proofs based on data structure (or lemma) A. Then, I refactored A to A', is there a general practice / tool facility for Coq to know all proofs are impacted by my refactoring?
Thank you for shedding some light on this matter.
edit1: thank you for all your suggestions, I will give them a try, and get back on this.
Another tool that might be useful is dpdgraph, which makes it possible to display all the usage dependence between various objects.
There is no such tool available, as far as I am aware. What I usually do is to refactor the code and try to repair it. Because of Coq's proofs and typing discipline, once the code compiles again, it is usually the case that it works.
You might want to take a look at PUMPKIN PATCH (GitHub repo). Here's a quote from the project readme file:
This is a prototype plugin for finding patches for broken Coq proofs. To use PUMPKIN, the programmer modifies a single proof script to provide an example adaptation of a proof to a change. PUMPKIN generalizes this example into a reusable patch which can be used to fix other broken proofs.
Not sure if this is exactly what you're looking for but it might be of interest.
In my coq development I am learning how to create new tactics tailored to my problem domain, a la Prof. Adam Chlipala.
On that page he describes how to create powerful tactics by wrapping repeat around a match that responds to various interesting conditions. The repeat then iterates, allowing for far-reaching inference.
The use of repeat has a caveat (emphasis mine):
The repeat that we use here is called a tactical, or tactic combinator. The behavior of repeat t is to loop through running t, running t on all generated subgoals, running t on their generated subgoals, and so on. When t fails at any point in this search tree, that particular subgoal is left to be handled by later tactics. Thus, it is important never to use repeat with a tactic that always succeeds.
Now, I already have a powerful tactic in use, auto. It similarly strings together chains of steps, this time found from hint databases. From auto's page:
auto either solves completely the goal or else leaves it intact. auto and trivial never fail.
Boo! I have already invested some effort in curating auto's hint databases, but it seems I am forbidden from employing them in tactics using repeat (that is, interesting tactics.)
Is there some variation of auto that can fail, or otherwise be used correctly in loops?
For example, perhaps this variant fails when it "leaves [the goal] intact".
EDIT: Incorporating auto into loops isn't the "right" way to do it anyway (see this), but the actual question of a failing version of auto is still perhaps interesting.
As mentioned by #AntonTrunov you can always use the progress tactical to make the tactic fail if the goal has not been changed. In the case of auto since it is supposed to solve the goal or leave it unchanged, you can also wrap it in solve [ auto ] which will have the same effect because it will fail if auto does not solve the goal completely (here is the doc for solve).
In my coq development I am learning how to create new tactics tailored to my problem domain, a la Prof. Adam Chlipala. On that page he describes how to create powerful custom tactics by e.g. combining repeat with match.
Now, I already have a powerful one-shot tactic in use, auto. It strings together chains of steps found from hint databases. I have invested some effort in curating those hint databases, so I'd like to continue using it as well.
However this presents a problem. It isn't clear what the "right" way is to incorporate auto's functionality into customized tactics.
For example, since (per its page) auto always either solves the goal or does nothing, putting it inside a loop is no more powerful than calling it once after the loop.
To see why this isn't ideal, consider a hypothetical way to directly call a single "step" of auto, which succeeds if it could make a change (as opposed to only when it solved the goal) and fails otherwise. Such single-steps could be interleaved with custom behavior in a match repeat loop, allowing us to e.g. try contradiction or try congruence at intermediate points within the search tree.
Are there good design patterns for incorporating auto's functionality into custom tactics?
Can auto's behavior be decomposed into "single step" tactics that we can use?
What I would do instead would be to incorporate other tactics within auto.
You can do so by using the Hint Extern num pat => mytactic : mybase command where num is a priority number (0 being the highest priority), pat a pattern to filter when the hint should be used and mytactic and mybase are of course the tactic you want to apply and the base you want to add the hint to (do not use the default core; build up your custom base instead and call it with auto with mybase; if you do not want to include the lemmas from the core base in the search, add the fake base nocore: auto with mybase nocore).
If you start relying on auto very much, I would switch instead to the almost equivalent but better behaved typeclasses eauto with mybase. Contrary to what its name suggests, it is a general purpose tactic that has nothing to do with type classes (as long as you explicitly provide the hint base on which it should be working). One of the main behavior difference to know is that the search depth is unbounded by default. So beware of possible infinite loops or fix a finite limit with the variant typeclasses eauto num with mybase.