diff --git a/docs/Style.thy b/docs/Style.thy index 0dfcde2b12..48ec6b1366 100644 --- a/docs/Style.thy +++ b/docs/Style.thy @@ -66,6 +66,7 @@ text \ * Don't mix object and meta logic in a lemma statement.\ + section \Text and comments\ text \ @@ -87,11 +88,18 @@ text \ the closing bracket on the same line as the ending text to not waste too much vertical space. Indent text by 2 inside the @{command text} area. This achieves visual separation.\ + section \Indentation\ text \ - Isabelle code is much easier to maintain when indented consistently. In apply style proofs we - indent by 2 spaces, and add an additional space for every additional subgoal. + Isabelle code is much easier to maintain when indented consistently. + When in doubt and not constrained by vertically aligning items or subgoal-count offsets, use + 2 spaces when indenting something with respect to its container (see ``General layout`` in + ``Other`` section). + + In apply style proofs we indent by 2 spaces, and add an additional space for every additional + subgoal. For instance, a command which applies when there are 3 subgoals should be indented by + 4 spaces. In the following example, the rules iffI and conjI add a new subgoal, and fast removes a subgoal. The idea is that, when something breaks, the indentation tells you whether a tactic used to solve @@ -219,6 +227,43 @@ lemma test_lemma3: case_tac h; simp) done + +section \Fact transformers and attributes\ + +text \ + For simple cases, standard approach applies: comma-separated list with one space after commas:\ + +lemmas attr1 = conj_absorb[THEN iffD2, OF conj_absorb, simplified] \ \basic case\ + +text \ + When the transform is more complex or runs out of horizontal room, wrapping is needed. + In most cases, reconfiguring the attributes into a vertical list should suffice:\ + +lemmas attr2 = conj_absorb[THEN iffD2, + OF conj_absorb[where A="A \ B \ C \ D \ E \ F \ G" for A B C D E F G, + simplified], + simplified] \ \simple wrapping case\ + +text \ + When terms get even larger, the transforms more complicated, or we start running into the column + limit, more wrapping is needed. We can gain extra space by indenting from the fact name:\ + +lemmas attr3 = conj_absorb[ \ \note the @{text "["} to indicate transform\ + THEN iffD2, + OF conj_absorb[where A="A \ B \ C \ D \ E \ F \ G" for A B C D E F G, + simplified], + simplified] \ \extreme wrapping case\ + +text \ + There is an important principle here: telling apart transformed/attributed facts from unaltered + facts at a glance. In other words avoid:\ + +lemmas attrb = conj_absorb \ \BAD: at first glance looks to be an unmodified fact\ + [THEN iffD2 (*...*)] + +lemmas attrb2 = conj_absorb [THEN iffD2 (*...*)] \ \avoid: still needs some mental processing\ + + section \Right vs left operator-wrapping\ text \ @@ -351,6 +396,72 @@ term " B \ A" \ \NOT OK: implies this parses as @{text "((A \ B) \ B) \ A"}\ + +section \Wrapping/indenting complex rule instantiations, usually as part of @{text "_tac"} methods\ + +text \ + This section concerns @{text "_tac"} methods, which are generally used when the instantiations + contain bound variables. When bound variables do no occur, prefer instantiations via attribute + (@{text "fact[where ...]"}) as they are more general.\ + +text \ + For simple instantiations which can fit on one line, style them as follows. + Notes: + * for single-variable instantiations, do not use quotes + * no space between @{text "="} and the instantiation or start of quote\ + +lemma + "\a; b\ \ a \ b" + apply (frule_tac P=a and Q="id b" in conjI) \ \GOOD\ + apply (frule_tac P="a" and Q = "id b" in conjI) \ \BAD: unnecessary quotes, unnecessary spacing\ + oops + +text \ + However, when the instantiation is complex, the instantiations, @{text "and"} and @{text "in"} + need to be distributed over multiple lines.\ + +lemma conjI3: + "\a; b; c\ \ a \ b \ c" + by simp + +text \ + For left operator-wrapping style, use this version. It was chosen based on being space-optimising + and nice-looking (variable instantiations and rule all left-align, while operators right-align):\ + +lemma \ \left operator-wrapping pretty version - preferred\ + "\ x; y; z \ \ x \ y \ z" + apply (drule_tac a=x + and b=y + and c=z + in conjI3) + oops + +text \ + For right-operator wrapping style, use this version. It still provides the alignment of variable + instantiations, but provides less horizontal space for the instantiation bodies themselves:\ + +lemma \ \right operator-wrapping pretty version - preferred\ + "\ x; y; z \ \ x \ y \ z" + apply (drule_tac a=x and + b=y and + c=z + in conjI3) \ \this must not go on previous line in multi-line instantiations\ + oops + +text \ + There is one more left-operator wrappings style we permit, but only due to legacy proofs and the + possibility of being understandable/generatable by tools. Please do not use it on new + hand-written lemmas:\ + +lemma \ \left operator-wrapping pretty version for tools/legacy - permitted\ + "\ x; y; z \ \ x \ y \ z" + apply (drule_tac a=x + and b=y + and c=z + in conjI3) + oops + + section \Other\ text \ @@ -365,6 +476,7 @@ text \ * Avoid commands that produce "legacy" warnings. Add an issue with tag cleanup if you see them after an Isabelle update.\ + section \Comments\ text \