@@ -560,7 +560,7 @@ Inductive JMeq (A : Type) (x : A) : forall B : Type, B -> Prop :=
]]
[JMeq]standsfor"John Major equality,"anamecoinedbyConorMcBrideasasortofpunaboutBritishpolitics.[JMeq]startsoutlookingalotlike[eq].Thecrucialdifferenceisthatwemayuse[JMeq]%\textit{%#<i>#onargumentsofdifferenttypes#</i>#%}%.Forinstance,alemmathatwefailedtoestablishbeforeistrivialwith[JMeq].Itmakesforprettiertheoremstatementstodefinesomesyntacticshorthandfirst.*)
[JMeq]standsfor%``%#"#John Major equality,#"#%''%anamecoinedbyConorMcBrideasasortofpunaboutBritishpolitics.[JMeq]startsoutlookingalotlike[eq].Thecrucialdifferenceisthatwemayuse[JMeq]%\textit{%#<i>#onargumentsofdifferenttypes#</i>#%}%.Forinstance,alemmathatwefailedtoestablishbeforeistrivialwith[JMeq].Itmakesforprettiertheoremstatementstodefinesomesyntacticshorthandfirst.*)
Infix"==":=JMeq(atlevel70,noassociativity).
...
...
@@ -734,7 +734,7 @@ Theorem JMeq_eq' : forall (A : Type) (x y : A),
@@ -500,6 +500,7 @@ Infix "@" := plug (no associativity, at level 60).
(** Finally, we have the step relation itself, which combines our ingredients in the standard way. In the congruence rule, we introduce the extra variable [E1] and its associated equality to make the rule easier for [eauto] to apply. *)
(** printing ==> $\Rightarrow$ *)
Reserved Notation "E1==>E2" (no associativity, at level 90).
Inductive Step : forall t, Exp t -> Exp t -> Prop :=
...
...
@@ -579,6 +580,7 @@ Qed.
We must start by defining the big-step semantics itself. The definition is completely standard. *)
(** printing ===> $\Longrightarrow$ *)
Reserved Notation "E1===>E2" (no associativity, at level 90).
Inductive BigStep : forall t, Exp t -> Exp t -> Prop :=
...
...
@@ -606,6 +608,7 @@ Hint Constructors BigStep.
(** To prove a crucial intermediate lemma, we will want to name the transitive-reflexive closure of the small-step relation. *)
(* begin thide *)
(** printing ==>* $\Rightarrow^*$ *)
Reserved Notation "E1==>*E2" (no associativity, at level 90).
Inductive MultiStep : forall t, Exp t -> Exp t -> Prop :=
%\noindent%...whichcorrespondsto"proof by case analysis"inclassicalmath.Fornon-recursiveinductivetypes,thetwotacticswillalwayshaveidenticalbehavior.Oftencaseanalysisissufficient,eveninproofsaboutrecursivetypes,anditisnicetoavoidintroducingunneededinductionhypotheses.
%\noindent%...whichcorrespondsto%``%#"#proof by case analysis#"#%''%inclassicalmath.Fornon-recursiveinductivetypes,thetwotacticswillalwayshaveidenticalbehavior.Oftencaseanalysisissufficient,eveninproofsaboutrecursivetypes,anditisnicetoavoidintroducingunneededinductionhypotheses.
Coq rejects this definition, saying "Recursivecalltonat_tree_ind'hasprincipalargumentequalto"tr"insteadofrest." There is no deep theoretical reason why this program should be rejected; Coq applies incomplete termination-checking heuristics, and it is necessary to learn a few of the most important rules. The term "nestedinductivetype" hints at the solution to this particular problem. Just like true mutually-inductive types require mutually-recursive induction principles, nested types require nested recursion. *)
Coq rejects this definition, saying %``%#"#Recursivecalltonat_tree_ind'hasprincipalargumentequalto"tr"insteadofrest.#"#%''% There is no deep theoretical reason why this program should be rejected; Coq applies incomplete termination-checking heuristics, and it is necessary to learn a few of the most important rules. The term %``%#"#nestedinductivetype#"#%''% hints at the solution to this particular problem. Just like true mutually-inductive types require mutually-recursive induction principles, nested types require nested recursion. *)
Fixpoint nat_tree_ind' (tr : nat_tree) : P tr :=
match tr with
...
...
@@ -1051,7 +1051,7 @@ The advantage of using the hint is not very clear here, because the original pro
Theorem true_neq_false : true <> false.
(* begin thide *)
(** We begin with the tactic [red], which is short for "onestepofreduction," to unfold the definition of logical negation. *)
(** We begin with the tactic [red], which is short for %``%#"#onestepofreduction,#"#%''% to unfold the definition of logical negation. *)
red.
(** [[
...
...
@@ -1128,11 +1128,11 @@ Qed.
(** %\begin{enumerate}%#<ol>#
%\item%#<li># Define an inductive type [truth] with three constructors, [Yes], [No], and [Maybe]. [Yes] stands for certain truth, [No] for certain falsehood, and [Maybe] for an unknown situation. Define "not," "and," and "or" for this replacement boolean algebra. Prove that your implementation of "and" is commutative and distributes over your implementation of "or."#</li>#
%\item%#<li># Define an inductive type [truth] with three constructors, [Yes], [No], and [Maybe]. [Yes] stands for certain truth, [No] for certain falsehood, and [Maybe] for an unknown situation. Define %``%#"#not,#"#%''% %``%#"#and,#"#%''% and %``%#"#or#"#%''% for this replacement boolean algebra. Prove that your implementation of %``%#"#and#"#%''% is commutative and distributes over your implementation of %``%#"#or.#"#%''%#</li>#
%\item%#<li># Modify the first example language of Chapter 2 to include variables, where variables are represented with [nat]. Extend the syntax and semantics of expressions to accommodate the change. Your new [expDenote] function should take as a new extra first argument a value of type [var -> nat], where [var] is a synonym for naturals-as-variables, and the function assigns a value to each variable. Define a constant folding function which does a bottom-up pass over an expression, at each stage replacing every binary operation on constants with an equivalent constant. Prove that constant folding preserves the meanings of expressions.#</li>#
%\item%#<li># Reimplement the second example language of Chapter 2 to use mutually-inductive types instead of dependent types. That is, define two separate (non-dependent) inductive types [nat_exp] and [bool_exp] for expressions of the two different types, rather than a single indexed type. To keep things simple, you may consider only the binary operators that take naturals as operands. Add natural number variables to the language, as in the last exercise, and add an "if" expression form taking as arguments one boolean expression and two natural number expressions. Define semantics and constant-folding functions for this new language. Your constant folding should simplify not just binary operations (returning naturals or booleans) with known arguments, but also "if" expressions with known values for their test expressions but possibly undetermined "then" and "else" cases. Prove that constant-folding a natural number expression preserves its meaning.#</li>#
%\item%#<li># Reimplement the second example language of Chapter 2 to use mutually-inductive types instead of dependent types. That is, define two separate (non-dependent) inductive types [nat_exp] and [bool_exp] for expressions of the two different types, rather than a single indexed type. To keep things simple, you may consider only the binary operators that take naturals as operands. Add natural number variables to the language, as in the last exercise, and add an %``%#"#if#"#%''% expression form taking as arguments one boolean expression and two natural number expressions. Define semantics and constant-folding functions for this new language. Your constant folding should simplify not just binary operations (returning naturals or booleans) with known arguments, but also %``%#"#if#"#%''% expressions with known values for their test expressions but possibly undetermined %``%#"#then#"#%''% and %``%#"#else#"#%''% cases. Prove that constant-folding a natural number expression preserves its meaning.#</li>#
%\item%#<li># Using a reflexive inductive definition, define a type [nat_tree] of infinitary trees, with natural numbers at their leaves and a countable infinity of new trees branching out of each internal node. Define a function [increment] that increments the number in every leaf of a [nat_tree]. Define a function [leapfrog] over a natural [i] and a tree [nt]. [leapfrog] should recurse into the [i]th child of [nt], the [i+1]st child of that node, the [i+2]nd child of the next node, and so on, until reaching a leaf, in which case [leapfrog] should return the number at that leaf. Prove that the result of any call to [leapfrog] is incremented by one by calling [increment] on the tree.#</li>#
@@ -74,7 +74,7 @@ There are a good number of (though definitely not "many") tools that are in wide
</table>
#
Isabelle/HOL,implementedwiththe"proof assistant development framework"Isabelle,isthemostpopularproofassistantfortheHOLlogic.TheotherimplementationsofHOLcanbeconsideredequivalentforpurposesofthediscussionhere.
Isabelle/HOL,implementedwiththe%``%#"#proof assistant development framework#"#%''%Isabelle,isthemostpopularproofassistantfortheHOLlogic.TheotherimplementationsofHOLcanbeconsideredequivalentforpurposesofthediscussionhere.
*)
...
...
@@ -111,9 +111,9 @@ Dependent types are not just useful because they help you express correctness pr
Isabelle/HOLandCoqbothsupportcodingnewproofmanipulationsinMLinwaysthatcannotleadtotheacceptanceofinvalidproofs.Additionally,Coqincludesadomain-specificlanguageforcodingdecisionproceduresinnormalCoqsourcecode,withnoneedtobreakoutintoML.ThislanguageiscalledLtac,andIthinkofitastheunsungherooftheproofassistantworld.NotonlydoesLtacpreventyoufrommakingfatalmistakes,italsoincludesanumberofnovelprogrammingconstructswhichcombinetomakea"proof by decision procedure"styleverypleasant.Wewillmeetthesefeaturesinthechapterstocome.
Isabelle/HOLandCoqbothsupportcodingnewproofmanipulationsinMLinwaysthatcannotleadtotheacceptanceofinvalidproofs.Additionally,Coqincludesadomain-specificlanguageforcodingdecisionproceduresinnormalCoqsourcecode,withnoneedtobreakoutintoML.ThislanguageiscalledLtac,andIthinkofitastheunsungherooftheproofassistantworld.NotonlydoesLtacpreventyoufrommakingfatalmistakes,italsoincludesanumberofnovelprogrammingconstructswhichcombinetomakea%``%#"#proof by decision procedure#"#%''%styleverypleasant.Wewillmeetthesefeaturesinthechapterstocome.
Incomparisonswithitscompetitors,Coqisoftenderidedforpromotingunreadableproofs.Itisveryeasytowriteproofscriptsthatmanipulateproofgoalsimperatively,withnostructuretoaidreaders.Suchdevelopmentsarenightmarestomaintain,andtheycertainlydonotmanagetoconvey"why the theorem is true"toanyonebuttheoriginalauthor.Oneadditional(andnotinsignificant)purposeofthisbookistoshowwhyitisunfairandunproductivetodismissCoqbasedontheexistenceofsuchdevelopments.
Incomparisonswithitscompetitors,Coqisoftenderidedforpromotingunreadableproofs.Itisveryeasytowriteproofscriptsthatmanipulateproofgoalsimperatively,withnostructuretoaidreaders.Suchdevelopmentsarenightmarestomaintain,andtheycertainlydonotmanagetoconvey%``%#"#why the theorem is true#"#%''%toanyonebuttheoriginalauthor.Oneadditional(andnotinsignificant)purposeofthisbookistoshowwhyitisunfairandunproductivetodismissCoqbasedontheexistenceofsuchdevelopments.
Afterwritingthiscode,evenIdonotunderstandtheprecisedetailsofhowbalancingworks.IconsultedChrisOkasaki'spaper"Red-Black Trees in a Functional Setting"andtranscribedthecodetousedependenttypes.Luckily,thedetailsarenotsoimportanthere;typesalonewilltellusthatinsertionpreservesbalanced-ness,andwewillprovethatinsertionproducestreescontainingtherightkeys.
Afterwritingthiscode,evenIdonotunderstandtheprecisedetailsofhowbalancingworks.IconsultedChrisOkasaki'spaper%``%#"#Red-Black Trees in a Functional Setting#"#%''%andtranscribedthecodetousedependenttypes.Luckily,thedetailsarenotsoimportanthere;typesalonewilltellusthatinsertionpreservesbalanced-ness,andwewillprovethatinsertionproducestreescontainingtherightkeys.
Ofcourse,thiskindofdefinitionisnotstructurallyrecursive,soCoqwillnotallowit.Getting"substitution for free"seemstorequiresomesimilarkindofself-reference.
Ofcourse,thiskindofdefinitionisnotstructurallyrecursive,soCoqwillnotallowit.Getting%``%#"#substitution for free#"#%''%seemstorequiresomesimilarkindofself-reference.
Hencethedistinctionbetween[bool]and[Prop].Programsoftype[bool]arecomputationalbyconstruction;wecanalwaysrunthemtodeterminetheirresults.Many[Prop]sareundecidable,andsowecanwritemoreexpressiveformulaswith[Prop]sthanwith[bool]s,buttheinevitableconsequenceisthatwecannotsimply"run a [Prop] to determine its truth."
Hencethedistinctionbetween[bool]and[Prop].Programsoftype[bool]arecomputationalbyconstruction;wecanalwaysrunthemtodeterminetheirresults.Many[Prop]sareundecidable,andsowecanwritemoreexpressiveformulaswith[Prop]sthanwith[bool]s,buttheinevitableconsequenceisthatwecannotsimply%``%#"#run a [Prop] to determine its truth.#"#%''%
@@ -341,7 +341,7 @@ We will see more about Coq's program extraction facility in a later chapter. Ho
(***First-OrderLogic*)
(**The[forall]connectiveoffirst-orderlogic,whichwehaveseeninmanyexamplessofar,isbuiltintoCoq.Gettingaheadofourselvesabit,wecanseeitasthedependentfunctiontypeconstructor.Infact,implicationanduniversalquantificationarejustdifferentsyntacticshorthandsforthesameCoqmechanism.Aformula[P->Q]isequivalentto[forallx:P,Q],where[x]doesnotappearin[Q].Thatis,the"real"typeoftheimplicationsays"for every proof of [P], there exists a proof of [Q]."
(**The[forall]connectiveoffirst-orderlogic,whichwehaveseeninmanyexamplessofar,isbuiltintoCoq.Gettingaheadofourselvesabit,wecanseeitasthedependentfunctiontypeconstructor.Infact,implicationanduniversalquantificationarejustdifferentsyntacticshorthandsforthesameCoqmechanism.Aformula[P->Q]isequivalentto[forallx:P,Q],where[x]doesnotappearin[Q].Thatis,the%``%#"#real#"#%''%typeoftheimplicationsays%``%#"#for every proof of [P], there exists a proof of [Q].#"#%''%
WhydoesCoqusethisrestriction?Wewilldiscusstheissueindetailinafuturechapter,whenweseethedependently-typedprogrammingtechniquesthatwouldallowustowritethisprooftermmanually.Fornow,wejustsaythatthealgorithmicproblemof"logically complete case analysis"isundecidablewhenphrasedinCoq'slogic.Afewtacticsanddesignpatternsthatwewillpresentinthischaptersufficeinalmostallcases.Forthecurrentexample,whatwewantisatacticcalled[inversion],whichcorrespondstotheconceptofinversionthatisfrequentlyusedwithnaturaldeductionproofsystems.*)
WhydoesCoqusethisrestriction?Wewilldiscusstheissueindetailinafuturechapter,whenweseethedependently-typedprogrammingtechniquesthatwouldallowustowritethisprooftermmanually.Fornow,wejustsaythatthealgorithmicproblemof%``%#"#logically complete case analysis#"#%''%isundecidablewhenphrasedinCoq'slogic.Afewtacticsanddesignpatternsthatwewillpresentinthischaptersufficeinalmostallcases.Forthecurrentexample,whatwewantisatacticcalled[inversion],whichcorrespondstotheconceptofinversionthatisfrequentlyusedwithnaturaldeductionproofsystems.*)
Undo.
inversion1.
...
...
@@ -658,7 +658,7 @@ Theorem even_plus : forall n m, even n -> even m -> even (n + m).
%\item%#<li>#Defineabig-stepevaluationrelation[eval],capturingwhatitmeansforanexpressiontoevaluatetoavalueunderaparticularvariableassignment."Big step"meansthattheevaluationofeveryexpressionshouldbeprovedwithasingleinstanceoftheinductivepredicateyouwilldefine.Forinstance,"[1 + 1] evaluates to [2] under assignment [va]"shouldbederivableforanyassignment[va].#</li>#
%\item%#<li>#Defineabig-stepevaluationrelation[eval],capturingwhatitmeansforanexpressiontoevaluatetoavalueunderaparticularvariableassignment.%``%#"#Big step#"#%''%meansthattheevaluationofeveryexpressionshouldbeprovedwithasingleinstanceoftheinductivepredicateyouwilldefine.Forinstance,%``%#"#[1 + 1] evaluates to [2] under assignment [va]#"#%''%shouldbederivableforanyassignment[va].#</li>#
(**Thoughapencil-and-paperproofmightclockoutatthispoint,writing"by a routine induction on [e],"itturnsoutnottomakesensetoattackthisproofdirectly.Weneedtousethestandardtrickof%\textit{%#<i>#strengtheningtheinductionhypothesis#</i>#%}%.Wedothatbyprovinganauxiliarylemma:
(**Thoughapencil-and-paperproofmightclockoutatthispoint,writing%``%#"#by a routine induction on [e],#"#%''%itturnsoutnottomakesensetoattackthisproofdirectly.Weneedtousethestandardtrickof%\textit{%#<i>#strengtheningtheinductionhypothesis#</i>#%}%.Wedothatbyprovinganauxiliarylemma:
*)
Lemmacompile_correct':foralleps,
...
...
@@ -585,7 +585,7 @@ ML and Haskell have indexed algebraic datatypes. For instance, their list types
(**Sofar,wehaveseenmanyexamplesofwhatwemightcall"classical program verification."Wewriteprograms,writetheirspecifications,andthenprovethattheprogramssatisfytheirspecifications.TheprogramsthatwehavewritteninCoqhavebeennormalfunctionalprogramsthatwecouldjustaswellhavewritteninHaskellorML.Inthischapter,westartinvestigatingusesof%\textit{%#<i>#dependenttypes#</i>#%}%tointegrateprogramming,specification,andprovingintoasinglephase.*)
(**Sofar,wehaveseenmanyexamplesofwhatwemightcall%``%#"#classical program verification.#"#%''%Wewriteprograms,writetheirspecifications,andthenprovethattheprogramssatisfytheirspecifications.TheprogramsthatwehavewritteninCoqhavebeennormalfunctionalprogramsthatwecouldjustaswellhavewritteninHaskellorML.Inthischapter,westartinvestigatingusesof%\textit{%#<i>#dependenttypes#</i>#%}%tointegrateprogramming,specification,andprovingintoasinglephase.*)
(***IntroducingSubsetTypes*)
...
...
@@ -234,7 +234,7 @@ Definition pred_strong4 (n : nat) : n > 0 -> {m : nat | n = S m}.