Mercurial > cpdt > repo
comparison src/Large.v @ 433:5eebaaa9f952
Pass through Large, to incorporate new coqdoc features
author | Adam Chlipala <adam@chlipala.net> |
---|---|
date | Thu, 26 Jul 2012 16:22:57 -0400 |
parents | 5f25705a10ea |
children | a54a4a2ea6e4 |
comparison
equal
deleted
inserted
replaced
432:17d01e51256c | 433:5eebaaa9f952 |
---|---|
18 | 18 |
19 (** %\part{The Big Picture} | 19 (** %\part{The Big Picture} |
20 | 20 |
21 \chapter{Proving in the Large}% *) | 21 \chapter{Proving in the Large}% *) |
22 | 22 |
23 (** It is somewhat unfortunate that the term %``%#"#theorem proving#"#%''% looks so much like the word %``%#"#theory.#"#%''% Most researchers and practitioners in software assume that mechanized theorem proving is profoundly impractical. Indeed, until recently, most advances in theorem proving for higher-order logics have been largely theoretical. However, starting around the beginning of the 21st century, there was a surge in the use of proof assistants in serious verification efforts. That line of work is still quite new, but I believe it is not too soon to distill some lessons on how to work effectively with large formal proofs. | 23 (** It is somewhat unfortunate that the term "theorem proving" looks so much like the word "theory." Most researchers and practitioners in software assume that mechanized theorem proving is profoundly impractical. Indeed, until recently, most advances in theorem proving for higher-order logics have been largely theoretical. However, starting around the beginning of the 21st century, there was a surge in the use of proof assistants in serious verification efforts. That line of work is still quite new, but I believe it is not too soon to distill some lessons on how to work effectively with large formal proofs. |
24 | 24 |
25 Thus, this chapter gives some tips for structuring and maintaining large Coq developments. *) | 25 Thus, this chapter gives some tips for structuring and maintaining large Coq developments. *) |
26 | 26 |
27 | 27 |
28 (** * Ltac Anti-Patterns *) | 28 (** * Ltac Anti-Patterns *) |
29 | 29 |
30 (** In this book, I have been following an unusual style, where proofs are not considered finished until they are %\index{fully automated proofs}``%#"#fully automated,#"#%''% in a certain sense. Each such theorem is proved by a single tactic. Since Ltac is a Turing-complete programming language, it is not hard to squeeze arbitrary heuristics into single tactics, using operators like the semicolon to combine steps. In contrast, most Ltac proofs %``%#"#in the wild#"#%''% consist of many steps, performed by individual tactics followed by periods. Is it really worth drawing a distinction between proof steps terminated by semicolons and steps terminated by periods? | 30 (** In this book, I have been following an unusual style, where proofs are not considered finished until they are %\index{fully automated proofs}%"fully automated," in a certain sense. Each such theorem is proved by a single tactic. Since Ltac is a Turing-complete programming language, it is not hard to squeeze arbitrary heuristics into single tactics, using operators like the semicolon to combine steps. In contrast, most Ltac proofs "in the wild" consist of many steps, performed by individual tactics followed by periods. Is it really worth drawing a distinction between proof steps terminated by semicolons and steps terminated by periods? |
31 | 31 |
32 I argue that this is, in fact, a very important distinction, with serious consequences for a majority of important verification domains. The more uninteresting drudge work a proof domain involves, the more important it is to work to prove theorems with single tactics. From an automation standpoint, single-tactic proofs can be extremely effective, and automation becomes more and more critical as proofs are populated by more uninteresting detail. In this section, I will give some examples of the consequences of more common proof styles. | 32 I argue that this is, in fact, a very important distinction, with serious consequences for a majority of important verification domains. The more uninteresting drudge work a proof domain involves, the more important it is to work to prove theorems with single tactics. From an automation standpoint, single-tactic proofs can be extremely effective, and automation becomes more and more critical as proofs are populated by more uninteresting detail. In this section, I will give some examples of the consequences of more common proof styles. |
33 | 33 |
34 As a running example, consider a basic language of arithmetic expressions, an interpreter for it, and a transformation that scales up every constant in an expression. *) | 34 As a running example, consider a basic language of arithmetic expressions, an interpreter for it, and a transformation that scales up every constant in an expression. *) |
35 | 35 |
133 | 133 |
134 Abort. | 134 Abort. |
135 | 135 |
136 (** Can you spot what went wrong, without stepping through the script step-by-step? The problem is that [trivial] never fails. Originally, [trivial] had been succeeding in proving an equality that follows by reflexivity. Our change to [times] leads to a case where that equality is no longer true. The invocation [trivial] happily leaves the false equality in place, and we continue on to the span of tactics intended for the second inductive case. Unfortunately, those tactics end up being applied to the _first_ case instead. | 136 (** Can you spot what went wrong, without stepping through the script step-by-step? The problem is that [trivial] never fails. Originally, [trivial] had been succeeding in proving an equality that follows by reflexivity. Our change to [times] leads to a case where that equality is no longer true. The invocation [trivial] happily leaves the false equality in place, and we continue on to the span of tactics intended for the second inductive case. Unfortunately, those tactics end up being applied to the _first_ case instead. |
137 | 137 |
138 The problem with [trivial] could be %``%#"#solved#"#%''% by writing, e.g., [solve [ trivial ]] instead, so that an error is signaled early on if something unexpected happens. However, the root problem is that the syntax of a tactic invocation does not imply how many subgoals it produces. Much more confusing instances of this problem are possible. For example, if a lemma [L] is modified to take an extra hypothesis, then uses of [apply L] will generate more subgoals than before. Old unstructured proof scripts will become hopelessly jumbled, with tactics applied to inappropriate subgoals. Because of the lack of structure, there is usually relatively little to be gleaned from knowledge of the precise point in a proof script where an error is raised. *) | 138 The problem with [trivial] could be "solved" by writing, e.g., [solve [ trivial ]] instead, so that an error is signaled early on if something unexpected happens. However, the root problem is that the syntax of a tactic invocation does not imply how many subgoals it produces. Much more confusing instances of this problem are possible. For example, if a lemma [L] is modified to take an extra hypothesis, then uses of [apply L] will generate more subgoals than before. Old unstructured proof scripts will become hopelessly jumbled, with tactics applied to inappropriate subgoals. Because of the lack of structure, there is usually relatively little to be gleaned from knowledge of the precise point in a proof script where an error is raised. *) |
139 | 139 |
140 Reset times. | 140 Reset times. |
141 | 141 |
142 Fixpoint times (k : nat) (e : exp) : exp := | 142 Fixpoint times (k : nat) (e : exp) : exp := |
143 match e with | 143 match e with |
256 IHe2 : eval e3 * eval e4 = eval e2 | 256 IHe2 : eval e3 * eval e4 = eval e2 |
257 ============================ | 257 ============================ |
258 eval e1 * eval e3 * eval e4 = eval e1 * eval e2 | 258 eval e1 * eval e3 * eval e4 = eval e1 * eval e2 |
259 ]] | 259 ]] |
260 | 260 |
261 [crush] does not know how to finish this goal. We could finish the proof manually. *) | 261 The [crush] tactic does not know how to finish this goal. We could finish the proof manually. *) |
262 | 262 |
263 rewrite <- IHe2; crush. | 263 rewrite <- IHe2; crush. |
264 | 264 |
265 (** However, the proof would be easier to understand and maintain if we separated this insight into a separate lemma. *) | 265 (** However, the proof would be easier to understand and maintain if we separated this insight into a separate lemma. *) |
266 | 266 |
455 | 455 |
456 (** The final subgoal is for multiplication, and it is here that we get stuck in the proof state summarized above. *) | 456 (** The final subgoal is for multiplication, and it is here that we get stuck in the proof state summarized above. *) |
457 | 457 |
458 t. | 458 t. |
459 | 459 |
460 (** What is [t] doing to get us to this point? The %\index{tactics!info}%[info] command can help us answer this kind of question. *) | 460 (** What is [t] doing to get us to this point? The %\index{tactics!info}%[info] command can help us answer this kind of question. (As of this writing, [info] is no longer functioning in the most recent Coq release, but I hope it returns.) *) |
461 | 461 |
462 Undo. | 462 Undo. |
463 info t. | 463 info t. |
464 | |
465 (* begin hide *) | |
466 Definition eir := eq_ind_r. | |
467 (* end hide *) | |
464 | 468 |
465 (** %\vspace{-.15in}%[[ | 469 (** %\vspace{-.15in}%[[ |
466 == simpl in *; intuition; subst; autorewrite with core in *; | 470 == simpl in *; intuition; subst; autorewrite with core in *; |
467 simpl in *; intuition; subst; autorewrite with core in *; | 471 simpl in *; intuition; subst; autorewrite with core in *; |
468 simpl in *; intuition; subst; destruct (reassoc e2). | 472 simpl in *; intuition; subst; destruct (reassoc e2). |
538 | 542 |
539 (** We prove a simple lemma very quickly, using the %\index{Vernacular commands!Time}%[Time] command to measure exactly how quickly. *) | 543 (** We prove a simple lemma very quickly, using the %\index{Vernacular commands!Time}%[Time] command to measure exactly how quickly. *) |
540 | 544 |
541 Lemma slow : forall x y, P x y -> Q x y -> S x y -> f x = f y. | 545 Lemma slow : forall x y, P x y -> Q x y -> S x y -> f x = f y. |
542 Time eauto 6. | 546 Time eauto 6. |
543 (** %\vspace{-.2in}%[[ | 547 (** << |
544 Finished transaction in 0. secs (0.068004u,0.s) | 548 Finished transaction in 0. secs (0.068004u,0.s) |
545 ]] | 549 >> |
546 *) | 550 *) |
547 | 551 |
548 Qed. | 552 Qed. |
549 | 553 |
550 (** Now we add a different hypothesis, which is innocent enough; in fact, it is even provable as a theorem. *) | 554 (** Now we add a different hypothesis, which is innocent enough; in fact, it is even provable as a theorem. *) |
551 | 555 |
552 Hypothesis H3 : forall x y, x = y -> f x = f y. | 556 Hypothesis H3 : forall x y, x = y -> f x = f y. |
553 | 557 |
554 Lemma slow' : forall x y, P x y -> Q x y -> S x y -> f x = f y. | 558 Lemma slow' : forall x y, P x y -> Q x y -> S x y -> f x = f y. |
555 Time eauto 6. | 559 Time eauto 6. |
556 (** %\vspace{-.2in}%[[ | 560 (** << |
557 Finished transaction in 2. secs (1.264079u,0.s) | 561 Finished transaction in 2. secs (1.264079u,0.s) |
558 ]] | 562 >> |
559 | 563 |
560 Why has the search time gone up so much? The [info] command is not much help, since it only shows the result of search, not all of the paths that turned out to be worthless. *) | 564 Why has the search time gone up so much? The [info] command is not much help, since it only shows the result of search, not all of the paths that turned out to be worthless. *) |
561 | 565 |
562 (* begin thide *) | 566 (* begin thide *) |
563 Restart. | 567 Restart. |
583 | 587 |
584 This output does not tell us why proof search takes so long, but it does provide a clue that would be useful if we had forgotten that we added transitivity as a hint. The [eauto] tactic is applying depth-first search, and the proof script where the real action is ends up buried inside a chain of pointless invocations of transitivity, where each invocation uses reflexivity to discharge one subgoal. Each increment to the depth argument to [eauto] adds another silly use of transitivity. This wasted proof effort only adds linear time overhead, as long as proof search never makes false steps. No false steps were made before we added the new hypothesis, but somehow the addition made possible a new faulty path. To understand which paths we enabled, we can use the %\index{tactics!debug}%[debug] command. *) | 588 This output does not tell us why proof search takes so long, but it does provide a clue that would be useful if we had forgotten that we added transitivity as a hint. The [eauto] tactic is applying depth-first search, and the proof script where the real action is ends up buried inside a chain of pointless invocations of transitivity, where each invocation uses reflexivity to discharge one subgoal. Each increment to the depth argument to [eauto] adds another silly use of transitivity. This wasted proof effort only adds linear time overhead, as long as proof search never makes false steps. No false steps were made before we added the new hypothesis, but somehow the addition made possible a new faulty path. To understand which paths we enabled, we can use the %\index{tactics!debug}%[debug] command. *) |
585 | 589 |
586 Restart. | 590 Restart. |
587 debug eauto 6. | 591 debug eauto 6. |
592 | |
593 (* begin hide *) | |
594 Definition deeeebug := (@eq_refl, @sym_eq). | |
595 (* end hide *) | |
588 | 596 |
589 (** The output is a large proof tree. The beginning of the tree is enough to reveal what is happening: | 597 (** The output is a large proof tree. The beginning of the tree is enough to reveal what is happening: |
590 [[ | 598 [[ |
591 1 depth=6 | 599 1 depth=6 |
592 1.1 depth=6 intro | 600 1.1 depth=6 intro |
624 | 632 |
625 (** As aggravating as the above situation may be, there is greater aggravation to be had from importing library modules with commands like %\index{Vernacular commands!Require Import}%[Require Import]. Such a command imports not just the Gallina terms from a module, but also all the hints for [auto], [eauto], and [autorewrite]. Some very recent versions of Coq include mechanisms for removing hints from databases, but the proper solution is to be very conservative in exporting hints from modules. Consider putting hints in named databases, so that they may be used only when called upon explicitly, as demonstrated in Chapter 13. | 633 (** As aggravating as the above situation may be, there is greater aggravation to be had from importing library modules with commands like %\index{Vernacular commands!Require Import}%[Require Import]. Such a command imports not just the Gallina terms from a module, but also all the hints for [auto], [eauto], and [autorewrite]. Some very recent versions of Coq include mechanisms for removing hints from databases, but the proper solution is to be very conservative in exporting hints from modules. Consider putting hints in named databases, so that they may be used only when called upon explicitly, as demonstrated in Chapter 13. |
626 | 634 |
627 It is also easy to end up with a proof script that uses too much memory. As tactics run, they avoid generating proof terms, since serious proof search will consider many possible avenues, and we do not want to build proof terms for subproofs that end up unused. Instead, tactic execution maintains%\index{thunks}% _thunks_ (suspended computations, represented with closures), such that a tactic's proof-producing thunk is only executed when we run %\index{Vernacular commands!Qed}%[Qed]. These thunks can use up large amounts of space, such that a proof script exhausts available memory, even when we know that we could have used much less memory by forcing some thunks earlier. | 635 It is also easy to end up with a proof script that uses too much memory. As tactics run, they avoid generating proof terms, since serious proof search will consider many possible avenues, and we do not want to build proof terms for subproofs that end up unused. Instead, tactic execution maintains%\index{thunks}% _thunks_ (suspended computations, represented with closures), such that a tactic's proof-producing thunk is only executed when we run %\index{Vernacular commands!Qed}%[Qed]. These thunks can use up large amounts of space, such that a proof script exhausts available memory, even when we know that we could have used much less memory by forcing some thunks earlier. |
628 | 636 |
629 The %\index{tactics!abstract}%[abstract] tactical helps us force thunks by proving some subgoals as their own lemmas. For instance, a proof [induction x; crush] can in many cases be made to use significantly less peak memory by changing it to [induction x; abstract crush]. The main limitation of [abstract] is that it can only be applied to subgoals that are proved completely, with no undetermined unification variables remaining. Still, many large automated proofs can realize vast memory savings via [abstract]. *) | 637 The %\index{tactics!abstract}%[abstract] tactical helps us force thunks by proving some subgoals as their own lemmas. For instance, a proof [induction x; crush] can in many cases be made to use significantly less peak memory by changing it to [induction x; abstract crush]. The main limitation of [abstract] is that it can only be applied to subgoals that are proved completely, with no undetermined unification variables in their initial states. Still, many large automated proofs can realize vast memory savings via [abstract]. *) |
630 | 638 |
631 | 639 |
632 (** * Modules *) | 640 (** * Modules *) |
633 | 641 |
634 (** Last chapter's examples of proof by reflection demonstrate opportunities for implementing abstract proof strategies with stronger formal guarantees than can be had with Ltac scripting. Coq's _module system_ provides another tool for more rigorous development of generic theorems. This feature is inspired by the module systems found in Standard ML%~\cite{modules}% and Objective Caml, and the discussion that follows assumes familiarity with the basics of one of those systems. | 642 (** Last chapter's examples of proof by reflection demonstrate opportunities for implementing abstract proof strategies with stronger formal guarantees than can be had with Ltac scripting. Coq's _module system_ provides another tool for more rigorous development of generic theorems. This feature is inspired by the module systems found in Standard ML%~\cite{modules}% and Objective Caml, and the discussion that follows assumes familiarity with the basics of one of those systems. |
744 (** As in ML, the module system provides an effective way to structure large developments. Unlike in ML, Coq modules add no expressiveness; we can implement any module as an inhabitant of a dependent record type. It is the second-class nature of modules that makes them easier to use than dependent records in many case. Because modules may only be used in quite restricted ways, it is easier to support convenient module coding through special commands and editing modes, as the above example demonstrates. An isomorphic implementation with records would have suffered from lack of such conveniences as module subtyping and importation of the fields of a module. On the other hand, all module values must be determined statically, so modules may not be computed, e.g., within the defintions of normal functions, based on particular function parameters. *) | 752 (** As in ML, the module system provides an effective way to structure large developments. Unlike in ML, Coq modules add no expressiveness; we can implement any module as an inhabitant of a dependent record type. It is the second-class nature of modules that makes them easier to use than dependent records in many case. Because modules may only be used in quite restricted ways, it is easier to support convenient module coding through special commands and editing modes, as the above example demonstrates. An isomorphic implementation with records would have suffered from lack of such conveniences as module subtyping and importation of the fields of a module. On the other hand, all module values must be determined statically, so modules may not be computed, e.g., within the defintions of normal functions, based on particular function parameters. *) |
745 | 753 |
746 | 754 |
747 (** * Build Processes *) | 755 (** * Build Processes *) |
748 | 756 |
757 (* begin hide *) | |
758 Module Lib. | |
759 Module A. | |
760 End A. | |
761 Module B. | |
762 End B. | |
763 Module C. | |
764 End C. | |
765 End Lib. | |
766 Module Client. | |
767 Module D. | |
768 End D. | |
769 Module E. | |
770 End E. | |
771 End Client. | |
772 (* end hide *) | |
773 | |
749 (** As in software development, large Coq projects are much more manageable when split across multiple files and when decomposed into libraries. Coq and Proof General provide very good support for these activities. | 774 (** As in software development, large Coq projects are much more manageable when split across multiple files and when decomposed into libraries. Coq and Proof General provide very good support for these activities. |
750 | 775 |
751 Consider a library that we will name [Lib], housed in directory %\texttt{%#<tt>#LIB#</tt>#%}% and split between files %\texttt{%#<tt>#A.v#</tt>#%}%, %\texttt{%#<tt>#B.v#</tt>#%}%, and %\texttt{%#<tt>#C.v#</tt>#%}%. A simple %\index{Makefile}%Makefile will compile the library, relying on the standard Coq tool %\index{coq\_makefile}\texttt{%#<tt>#coq_makefile#</tt>#%}% to do the hard work. | 776 Consider a library that we will name [Lib], housed in directory <<LIB>> and split between files <<A.v>>, <<B.v>>, and <<C.v>>. A simple %\index{Makefile}%Makefile will compile the library, relying on the standard Coq tool %\index{coq\_makefile}\texttt{%#<tt>#coq_makefile#</tt>#%}% to do the hard work. |
752 | 777 |
753 << | 778 << |
754 MODULES := A B C | 779 MODULES := A B C |
755 VS := $(MODULES:%=%.v) | 780 VS := $(MODULES:%=%.v) |
756 | 781 |
765 clean:: Makefile.coq | 790 clean:: Makefile.coq |
766 $(MAKE) -f Makefile.coq clean | 791 $(MAKE) -f Makefile.coq clean |
767 rm -f Makefile.coq | 792 rm -f Makefile.coq |
768 >> | 793 >> |
769 | 794 |
770 The Makefile begins by defining a variable %\texttt{%#<tt>#VS#</tt>#%}% holding the list of filenames to be included in the project. The primary target is %\texttt{%#<tt>#coq#</tt>#%}%, which depends on the construction of an auxiliary Makefile called %\texttt{%#<tt>#Makefile.coq#</tt>#%}%. Another rule explains how to build that file. We call %\texttt{%#<tt>#coq_makefile#</tt>#%}%, using the %\texttt{%#<tt>#-R#</tt>#%}% flag to specify that files in the current directory should be considered to belong to the library [Lib]. This Makefile will build a compiled version of each module, such that %\texttt{%#<tt>#X.v#</tt>#%}% is compiled into %\texttt{%#<tt>#X.vo#</tt>#%}%. | 795 The Makefile begins by defining a variable <<VS>> holding the list of filenames to be included in the project. The primary target is <<coq>>, which depends on the construction of an auxiliary Makefile called <<Makefile.coq>>. Another rule explains how to build that file. We call %\texttt{%#<tt>#coq_makefile#</tt>#%}%, using the <<-R>> flag to specify that files in the current directory should be considered to belong to the library [Lib]. This Makefile will build a compiled version of each module, such that <<X.v>> is compiled into <<X.vo>>. |
771 | 796 |
772 Now code in %\texttt{%#<tt>#B.v#</tt>#%}% may refer to definitions in %\texttt{%#<tt>#A.v#</tt>#%}% after running | 797 Now code in <<B.v>> may refer to definitions in <<A.v>> after running |
773 [[ | 798 [[ |
774 Require Import Lib.A. | 799 Require Import Lib.A. |
775 ]] | 800 ]] |
776 %\vspace{-.15in}%Library [Lib] is presented as a module, containing a submodule [A], which contains the definitions from %\texttt{%#<tt>#A.v#</tt>#%}%. These are genuine modules in the sense of Coq's module system, and they may be passed to functors and so on. | 801 %\vspace{-.15in}%Library [Lib] is presented as a module, containing a submodule [A], which contains the definitions from <<A.v>>. These are genuine modules in the sense of Coq's module system, and they may be passed to functors and so on. |
777 | 802 |
778 The command [Require Import] is a convenient combination of two more primitive commands. The %\index{Vernacular commands!Require}%[Require] command finds the %\texttt{%#<tt>#.vo#</tt>#%}% file containing the named module, ensuring that the module is loaded into memory. The %\index{Vernacular commands!Import}%[Import] command loads all top-level definitions of the named module into the current namespace, and it may be used with local modules that do not have corresponding %\texttt{%#<tt>#.vo#</tt>#%}% files. Another command, %\index{Vernacular commands!Load}%[Load], is for inserting the contents of a named file verbatim. It is generally better to use the module-based commands, since they avoid rerunning proof scripts, and they facilitate reorganization of directory structure without the need to change code. | 803 The command [Require Import] is a convenient combination of two more primitive commands. The %\index{Vernacular commands!Require}%[Require] command finds the <<.vo>> file containing the named module, ensuring that the module is loaded into memory. The %\index{Vernacular commands!Import}%[Import] command loads all top-level definitions of the named module into the current namespace, and it may be used with local modules that do not have corresponding <<.vo>> files. Another command, %\index{Vernacular commands!Load}%[Load], is for inserting the contents of a named file verbatim. It is generally better to use the module-based commands, since they avoid rerunning proof scripts, and they facilitate reorganization of directory structure without the need to change code. |
779 | 804 |
780 Now we would like to use our library from a different development, called [Client] and found in directory %\texttt{%#<tt>#CLIENT#</tt>#%}%, which has its own Makefile. | 805 Now we would like to use our library from a different development, called [Client] and found in directory <<CLIENT>>, which has its own Makefile. |
781 | 806 |
782 << | 807 << |
783 MODULES := D E | 808 MODULES := D E |
784 VS := $(MODULES:%=%.v) | 809 VS := $(MODULES:%=%.v) |
785 | 810 |
794 clean:: Makefile.coq | 819 clean:: Makefile.coq |
795 $(MAKE) -f Makefile.coq clean | 820 $(MAKE) -f Makefile.coq clean |
796 rm -f Makefile.coq | 821 rm -f Makefile.coq |
797 >> | 822 >> |
798 | 823 |
799 We change the %\texttt{%#<tt>#coq_makefile#</tt>#%}% call to indicate where the library [Lib] is found. Now %\texttt{%#<tt>#D.v#</tt>#%}% and %\texttt{%#<tt>#E.v#</tt>#%}% can refer to definitions from [Lib] module [A] after running | 824 We change the %\texttt{%#<tt>#coq_makefile#</tt>#%}% call to indicate where the library [Lib] is found. Now <<D.v>> and <<E.v>> can refer to definitions from [Lib] module [A] after running |
800 [[ | 825 [[ |
801 Require Import Lib.A. | 826 Require Import Lib.A. |
802 ]] | 827 ]] |
803 %\vspace{-.15in}\noindent{}%and %\texttt{%#<tt>#E.v#</tt>#%}% can refer to definitions from %\texttt{%#<tt>#D.v#</tt>#%}% by running | 828 %\vspace{-.15in}\noindent{}%and <<E.v>> can refer to definitions from <<D.v>> by running |
804 [[ | 829 [[ |
805 Require Import Client.D. | 830 Require Import Client.D. |
806 ]] | 831 ]] |
807 %\vspace{-.15in}%It can be useful to split a library into several files, but it is also inconvenient for client code to import library modules individually. We can get the best of both worlds by, for example, adding an extra source file %\texttt{%#<tt>#Lib.v#</tt>#%}% to [Lib]'s directory and Makefile, where that file contains just this line:%\index{Vernacular commands!Require Export}% | 832 %\vspace{-.15in}%It can be useful to split a library into several files, but it is also inconvenient for client code to import library modules individually. We can get the best of both worlds by, for example, adding an extra source file <<Lib.v>> to [Lib]'s directory and Makefile, where that file contains just this line:%\index{Vernacular commands!Require Export}% |
808 [[ | 833 [[ |
809 Require Export Lib.A Lib.B Lib.C. | 834 Require Export Lib.A Lib.B Lib.C. |
810 ]] | 835 ]] |
811 %\vspace{-.15in}%Now client code can import all definitions from all of [Lib]'s modules simply by running | 836 %\vspace{-.15in}%Now client code can import all definitions from all of [Lib]'s modules simply by running |
812 [[ | 837 [[ |
814 ]] | 839 ]] |
815 %\vspace{-.15in}%The two Makefiles above share a lot of code, so, in practice, it is useful to define a common Makefile that is included by multiple library-specific Makefiles. | 840 %\vspace{-.15in}%The two Makefiles above share a lot of code, so, in practice, it is useful to define a common Makefile that is included by multiple library-specific Makefiles. |
816 | 841 |
817 %\medskip% | 842 %\medskip% |
818 | 843 |
819 The remaining ingredient is the proper way of editing library code files in Proof General. Recall this snippet of %\texttt{%#<tt>#.emacs#</tt>#%}% code from Chapter 2, which tells Proof General where to find the library associated with this book. | 844 The remaining ingredient is the proper way of editing library code files in Proof General. Recall this snippet of <<.emacs>> code from Chapter 2, which tells Proof General where to find the library associated with this book. |
820 | 845 |
821 << | 846 << |
822 (custom-set-variables | 847 (custom-set-variables |
823 ... | 848 ... |
824 '(coq-prog-args '("-I" "/path/to/cpdt/src")) | 849 '(coq-prog-args '("-I" "/path/to/cpdt/src")) |
835 '(coq-prog-args '("-R" "LIB" "Lib" "-R" "CLIENT" "Client")) | 860 '(coq-prog-args '("-R" "LIB" "Lib" "-R" "CLIENT" "Client")) |
836 ... | 861 ... |
837 ) | 862 ) |
838 >> | 863 >> |
839 | 864 |
840 When working on multiple projects, it is useful to leave multiple versions of this setting in your %\texttt{%#<tt>#.emacs#</tt>#%}% file, commenting out all but one of them at any moment in time. To switch between projects, change the commenting structure and restart Emacs. | 865 When working on multiple projects, it is useful to leave multiple versions of this setting in your <<.emacs>> file, commenting out all but one of them at any moment in time. To switch between projects, change the commenting structure and restart Emacs. |
841 | 866 |
842 Alternatively, we can revisit the directory-local settings approach and write the following into a file %\texttt{%#<tt>#.dir-locals.el#</tt>#%}% in %\texttt{%#<tt>#CLIENT#</tt>#%}%: | 867 Alternatively, we can revisit the directory-local settings approach and write the following into a file <<.dir-locals.el>> in <<CLIENT>>: |
843 | 868 |
844 << | 869 << |
845 ((coq-mode . ((coq-prog-args . | 870 ((coq-mode . ((coq-prog-args . |
846 ("-emacs-U" "-R" "LIB" "Lib" "-R" "CLIENT" "Client"))))) | 871 ("-emacs-U" "-R" "LIB" "Lib" "-R" "CLIENT" "Client"))))) |
847 >> | 872 >> |