text\<open> In order to get a first idea of how Isabelle/Isar proof documents may look
like, we consider the propositions \<open>I\<close>, \<open>K\<close>, and \<open>S\<close>. The following (rather
explicit) proofs should require little extra explanations. \<close>
lemma I: "A \ A" proof assume A show A by fact qed
lemma K: "A \ B \ A" proof assume A show"B \ A" proof show A by fact qed qed
lemma S: "(A \ B \ C) \ (A \ B) \ A \ C" proof assume"A \ B \ C" show"(A \ B) \ A \ C" proof assume"A \ B" show"A \ C" proof assume A show C proof (rule mp) show"B \ C" by (rule mp) fact+ show B by (rule mp) fact+ qed qed qed qed
text\<open>
Isar provides several ways to fine-tune the reasoning, avoiding excessive
detail. Several abbreviated language elements are available, enabling the
writer to express proofs in a more concise way, even without referring to
any automated proof tools yet.
Concluding any (sub-)proof already involves solving any remaining goals by
assumption\<^footnote>\<open>This is not a completely trivial operation, as proof by
assumption may involve full higher-order unification.\<close>. Thus we may skip the
rather vacuous body of the above proof. \<close>
lemma"A \ A" proof qed
text\<open> Note that the \<^theory_text>\<open>proof\<close> command refers to the \<open>rule\<close> method (without
arguments) by default. Thus it implicitly applies a single rule, as
determined from the syntactic form of the statements involved. The \<^theory_text>\<open>by\<close>
command abbreviates any proofwith empty body, so the proof may be further
pruned. \<close>
lemma"A \ A" by rule
text\<open> Proofby a single rule may be abbreviated as double-dot. \<close>
lemma"A \ A" ..
text\<open> Thus we have arrived at an adequate representation of the proof of a
tautology that holds by a single standard rule.\<^footnote>\<open>Apparently, the
rule here is implication introduction.\<close>
\<^medskip> Let us also reconsider \<open>K\<close>. Its statement is composed of iterated
connectives. Basic decomposition isby a single rule at a time, which is why
our first version above was by nesting two proofs.
The \<open>intro\<close> proof method repeatedly decomposes a goal's conclusion.\<^footnote>\<open>The
dual method is\<open>elim\<close>, acting on a goal's premises.\<close> \<close>
lemma"A \ B \ A" proof (intro impI) assume A show A by fact qed
text\<open>Again, the body may be collapsed.\<close>
lemma"A \ B \ A" by (intro impI)
text\<open>
Just like \<open>rule\<close>, the \<open>intro\<close> and \<open>elim\<close> proof methods pick standard
structural rules, incase no explicit arguments are given. While implicit
rules are usually just fine for single rule application, this may go too far with iteration. Thusin practice, \<open>intro\<close> and \<open>elim\<close> would be typically
restricted to certain structures by giving a few rules only, e.g.\ \<^theory_text>\<open>proof
(intro impI allI)\<close> to strip implications and universal quantifiers.
Such well-tuned iterated decomposition of certain structures is the prime
application of \<open>intro\<close> and \<open>elim\<close>. In contrast, terminal steps that solve a
goal completely are usually performed by actual automated proof methods
(such as \<^theory_text>\<open>by blast\<close>. \<close>
subsection \<open>Variations of backward vs.\ forward reasoning\<close>
text\<open>
Certainly, any proof may be performed in backward-style only. On the other
hand, small steps of reasoning are often more naturally expressed in
forward-style. Isar supports both backward and forward reasoning as a
first-class concept. In order to demonstrate the difference, we consider
several proofs of \<open>A \<and> B \<longrightarrow> B \<and> A\<close>.
The first version is purely backward. \<close>
lemma"A \ B \ B \ A" proof assume"A \ B" show"B \ A" proof show B by (rule conjunct2) fact show A by (rule conjunct1) fact qed qed
text\<open>
Above, the projection rules \<open>conjunct1\<close> / \<open>conjunct2\<close> had to be named
explicitly, since the goals \<open>B\<close> and \<open>A\<close> did not provide any structural clue.
This may be avoided using\<^theory_text>\<open>from\<close> to focus on the \<open>A \<and> B\<close> assumption as the
current facts, enabling the use of double-dot proofs. Note that \<^theory_text>\<open>from\<close>
already does forward-chaining, involving the \<open>conjE\<close> rule here. \<close>
lemma"A \ B \ B \ A" proof assume"A \ B" show"B \ A" proof from\<open>A \<and> B\<close> show B .. from\<open>A \<and> B\<close> show A .. qed qed
text\<open> In the next version, we move the forward step one level upwards.
Forward-chaining from the most recent facts is indicated by the \<^theory_text>\<open>then\<close>
command. Thus the proof of \<open>B \<and> A\<close> from \<open>A \<and> B\<close> actually becomes an
elimination, rather than an introduction. The resulting proofstructure
directly corresponds to that of the \<open>conjE\<close> rule, including the repeated
goal proposition that is abbreviated as \<open>?thesis\<close> below. \<close>
lemma"A \ B \ B \ A" proof assume"A \ B" thenshow"B \ A" proof\<comment> \<open>rule \<open>conjE\<close> of \<open>A \<and> B\<close>\<close> assume B A thenshow ?thesis .. \<comment> \<open>rule \<open>conjI\<close> of \<open>B \<and> A\<close>\<close> qed qed
text\<open> In the subsequent version we flatten the structure of the main body by doing
forward reasoning all the time. Only the outermost decomposition step is
left as backward. \<close>
lemma"A \ B \ B \ A" proof assume"A \ B" from\<open>A \<and> B\<close> have A .. from\<open>A \<and> B\<close> have B .. from\<open>B\<close> \<open>A\<close> show "B \<and> A" .. qed
text\<open>
We can still push forward-reasoning a bit further, even at the risk of
getting ridiculous. Note that we force the initial proof step to do nothing
here, by referring to the \<open>-\<close> proof method. \<close>
lemma"A \ B \ B \ A" proof -
{ assume"A \ B" from\<open>A \<and> B\<close> have A .. from\<open>A \<and> B\<close> have B .. from\<open>B\<close> \<open>A\<close> have "B \<and> A" ..
} thenshow ?thesis .. \<comment> \<open>rule \<open>impI\<close>\<close> qed
text\<open> \<^medskip> With these examples we have shifted through a whole range from purely
backward to purely forward reasoning. Apparently, in the extreme ends we get
slightly ill-structured proofs, which also require much explicit naming of
either rules (backward) or local facts (forward).
The general lesson learned here is that good proof style would achieve just
the \<^emph>\<open>right\<close> balance of top-down backward decomposition, and bottom-up
forward composition. In general, there is no single best way to arrange some
pieces of formal reasoning, of course. Depending on the actual applications,
the intended audience etc., rules (and methods) on the one hand vs.\ facts
on the other hand haveto be emphasized in an appropriate way. This requires
the proof writer to develop good taste, and some practice, of course.
\<^medskip> For our example the most appropriate way of reasoning is probably the middle
one, with conjunction introduction done after elimination. \<close>
lemma"A \ B \ B \ A" proof assume"A \ B" thenshow"B \ A" proof assume B A thenshow ?thesis .. qed qed
subsection \<open>A few examples from ``Introduction to Isabelle''\<close>
text\<open>
We rephrase some of the basic reasoning examples of \<^cite>\<open>"isabelle-intro"\<close>, using HOL rather than FOL. \<close>
text\<open>
We consider the proposition \<open>P \<or> P \<longrightarrow> P\<close>. The proof below involves
forward-chaining from\<open>P \<or> P\<close>, followed by an explicit case-analysis on the
two \<^emph>\<open>identical\<close> cases. \<close>
lemma"P \ P \ P" proof assume"P \ P" thenshow P proof\<comment> \<open>rule \<open>disjE\<close>: \smash{$\infer{\<open>C\<close>}{\<open>A \<or> B\<close> & \infer*{\<open>C\<close>}{[\<open>A\<close>]} & \infer*{\<open>C\<close>}{[\<open>B\<close>]}}$}\<close> assume P show P by fact next assume P show P by fact qed qed
text\<open> Case splits are \<^emph>\<open>not\<close> hardwired into the Isar language as a special
feature. The \<^theory_text>\<open>next\<close> command used to separate the cases above is just a
short form of managing block structure.
\<^medskip> In general, applying proof methods may split up a goal into separate
``cases'', i.e.\ new subgoals with individual local assumptions. The
corresponding prooftext typically mimics this by establishing results in
appropriate contexts, separated by blocks.
In order to avoid too much explicit parentheses, the Isar system implicitly
opens an additional block for any new goal, the \<^theory_text>\<open>next\<close> statement then
closes one block level, opening a new one. The resulting behaviour is what
one would expect from separating cases, only that it is more flexible. E.g.\
an induction base case (which does not introduce local assumptions) would \<^emph>\<open>not\<close> require \<^theory_text>\<open>next\<close> to separate the subsequent step case.
\<^medskip> In our example the situation is even simpler, since the two cases actually
coincide. Consequently the proof may be rephrased as follows. \<close>
lemma"P \ P \ P" proof assume"P \ P" thenshow P proof assume P show P by fact show P by fact qed qed
text\<open>Again, the rather vacuous body of the proof may be collapsed. Thus the case analysis degenerates into two assumption steps, which
are implicitly performed when concluding the single rule step of the
double-dot proof as follows.\<close>
lemma"P \ P \ P" proof assume"P \ P" thenshow P .. qed
subsubsection \<open>A quantifier proof\<close>
text\<open> To illustrate quantifier reasoning, let us prove \<open>(\<exists>x. P (f x)) \<longrightarrow> (\<exists>y. P y)\<close>. Informally, this holds because any \<open>a\<close> with \<open>P (f a)\<close> may be taken as a witness for the second existential statement.
The first proofis rather verbose, exhibiting quite a lot of (redundant)
detail. It gives explicit rules, even with some instantiation. Furthermore,
we encounter two new language elements: the \<^theory_text>\<open>fix\<close> command augments the contextby some new ``arbitrary, but fixed'' element; the \<^theory_text>\<open>is\<close> annotation
binds term abbreviations by higher-order pattern matching. \<close>
lemma"(\x. P (f x)) \ (\y. P y)" proof assume"\x. P (f x)" thenshow"\y. P y" proof (rule exE) \<comment> \<open>rule \<open>exE\<close>: \smash{$\infer{\<open>B\<close>}{\<open>\<exists>x. A(x)\<close> & \infer*{\<open>B\<close>}{[\<open>A(x)\<close>]_x}}$}\<close> fix a assume"P (f a)" (is"P ?witness") thenshow ?thesis by (rule exI [of P ?witness]) qed qed
text\<open>
While explicit rule instantiation may occasionally improve readability of
certain aspects of reasoning, it is usually quite redundant. Above, the
basic proof outline gives already enough structural clues for the system to
infer both the rules and their instances (by higher-order unification). Thus
we may as well prune the text as follows. \<close>
lemma"(\x. P (f x)) \ (\y. P y)" proof assume"\x. P (f x)" thenshow"\y. P y" proof fix a assume"P (f a)" thenshow ?thesis .. qed qed
text\<open>
Explicit \<open>\<exists>\<close>-elimination as seen above can become quite cumbersome in
practice. The derived Isar language element ``\<^theory_text>\<open>obtain\<close>'' provides a more
handsome way to do generalized existence reasoning. \<close>
lemma"(\x. P (f x)) \ (\y. P y)" proof assume"\x. P (f x)" thenobtain a where"P (f a)" .. thenshow"\y. P y" .. qed
text\<open>
Technically, \<^theory_text>\<open>obtain\<close> is similar to \<^theory_text>\<open>fix\<close> and \<^theory_text>\<open>assume\<close> together with a
soundness proof of the elimination involved. Thus it behaves similar to any
other forward proof element. Alsonote that due to the nature of general
existence reasoning involved here, any result exported from the context of
an \<^theory_text>\<open>obtain\<close> statement may \<^emph>\<open>not\<close> refer to the parameters introduced there. \<close>
subsubsection \<open>Deriving rules in Isabelle\<close>
text\<open>
We derive the conjunction elimination rule from the corresponding
projections. The proofis quite straight-forward, since Isabelle/Isar
supports non-atomic goals and assumptions fully transparently. \<close>
theorem conjE: "A \ B \ (A \ B \ C) \ C" proof - assume"A \ B" assume r: "A \ B \ C" show C proof (rule r) show A by (rule conjunct1) fact show B by (rule conjunct2) fact qed qed
end
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.