doc-src/TutorialI/Types/Axioms.thy
author nipkow
Wed, 25 Oct 2000 18:24:33 +0200
changeset 10328 bf33cbd76c05
child 10362 c6b197ccf1f1
permissions -rw-r--r--
*** empty log message ***
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
10328
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
     1
(*<*)theory Axioms = Overloading:(*>*)
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
     2
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
     3
subsection{*Axioms*}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
     4
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
     5
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
     6
text{*Now we want to attach axioms to our classes. Then we can reason on the
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
     7
level of classes and the results will be applicable to all types in a class,
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
     8
just as in axiomatic mathematics. These ideas are demonstrated by means of
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
     9
our above ordering relations.
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    10
*}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    11
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    12
subsubsection{*Partial orders*}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    13
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    14
text{*
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    15
A \emph{partial order} is a subclass of @{text ordrel}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    16
where certain axioms need to hold:
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    17
*}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    18
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    19
axclass parord < ordrel
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    20
refl:    "x <<= x"
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    21
trans:   "\<lbrakk> x <<= y; y <<= z \<rbrakk> \<Longrightarrow> x <<= z"
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    22
antisym: "\<lbrakk> x <<= y; y <<= x \<rbrakk> \<Longrightarrow> x = y"
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    23
less_le: "x << y = (x <<= y \<and> x \<noteq> y)"
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    24
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    25
text{*\noindent
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    26
The first three axioms are the familiar ones, and the final one
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    27
requires that @{text"<<"} and @{text"<<="} are related as expected.
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    28
Note that behind the scenes, Isabelle has restricted the axioms to class
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    29
@{text parord}. For example, this is what @{thm[source]refl} really looks like:
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    30
@{thm[show_types]refl}.
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    31
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    32
We can now prove simple theorems in this abstract setting, for example
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    33
that @{text"<<"} is not symmetric:
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    34
*}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    35
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    36
lemma [simp]: "(x::'a::parord) << y \<Longrightarrow> (\<not> y << x) = True";
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    37
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    38
txt{*\noindent
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    39
The conclusion is not simply @{prop"\<not> y << x"} because the preprocessor
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    40
of the simplifier would turn this into @{prop"y << x = False"}, thus yielding
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    41
a nonterminating rewrite rule. In the above form it is a generally useful
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    42
rule.
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    43
The type constraint is necessary because otherwise Isabelle would only assume
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    44
@{text"'a::ordrel"} (as required in the type of @{text"<<"}), in
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    45
which case the proposition is not a theorem.  The proof is easy:
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    46
*}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    47
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    48
by(simp add:less_le antisym);
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    49
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    50
text{* We could now continue in this vein and develop a whole theory of
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    51
results about partial orders. Eventually we will want to apply these results
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    52
to concrete types, namely the instances of the class. Thus we first need to
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    53
prove that the types in question, for example @{typ bool}, are indeed
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    54
instances of @{text parord}:*}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    55
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    56
instance bool :: parord
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    57
apply intro_classes;
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    58
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    59
txt{*\noindent
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    60
This time @{text intro_classes} leaves us with the four axioms,
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    61
specialized to type @{typ bool}, as subgoals:
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    62
@{goals[display,show_types,indent=0]}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    63
Fortunately, the proof is easy for blast, once we have unfolded the definitions
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    64
of @{text"<<"} and @{text"<<="} at @{typ bool}:
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    65
*}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    66
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    67
apply(simp_all (no_asm_use) only: le_bool_def less_bool_def);
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    68
by(blast, blast, blast, blast);
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    69
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    70
text{*\noindent
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    71
Can you figure out why we have to include @{text"(no_asm_use)"}?
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    72
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    73
We can now apply our single lemma above in the context of booleans:
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    74
*}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    75
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    76
lemma "(P::bool) << Q \<Longrightarrow> \<not>(Q << P)";
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    77
by simp;
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    78
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    79
text{*\noindent
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    80
The effect is not stunning but demonstrates the principle.  It also shows
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    81
that tools like the simplifier can deal with generic rules as well. Moreover,
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    82
it should be clear that the main advantage of the axiomatic method is that
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    83
theorems can be proved in the abstract and one does not need to repeat the
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    84
proof for each instance.
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    85
*}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    86
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    87
subsubsection{*Linear orders*}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    88
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    89
text{* If any two elements of a partial order are comparable it is a
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    90
\emph{linear} or \emph{total} order: *}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    91
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    92
axclass linord < parord
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    93
total: "x <<= y \<or> y <<= x"
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    94
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    95
text{*\noindent
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    96
By construction, @{text linord} inherits all axioms from @{text parord}.
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    97
Therefore we can show that totality can be expressed in terms of @{text"<<"}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    98
as follows:
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
    99
*}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   100
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   101
lemma "\<And>x::'a::linord. x<<y \<or> x=y \<or> y<<x";
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   102
apply(simp add: less_le);
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   103
apply(insert total);
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   104
apply blast;
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   105
done
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   106
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   107
text{*
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   108
Linear orders are an example of subclassing by construction, which is the most
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   109
common case. It is also possible to prove additional subclass relationships
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   110
later on, i.e.\ subclassing by proof. This is the topic of the following
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   111
section.
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   112
*}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   113
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   114
subsubsection{*Strict orders*}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   115
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   116
text{*
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   117
An alternative axiomatization of partial orders takes @{text"<<"} rather than
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   118
@{text"<<="} as the primary concept. The result is a \emph{strict} order:
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   119
*}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   120
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   121
axclass strord < ordrel
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   122
irrefl:     "\<not> x << x"
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   123
less_trans: "\<lbrakk> x << y; y << z \<rbrakk> \<Longrightarrow> x << z"
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   124
le_less:    "x <<= y = (x << y \<or> x = y)"
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   125
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   126
text{*\noindent
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   127
It is well known that partial orders are the same as strict orders. Let us
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   128
prove one direction, namely that partial orders are a subclass of strict
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   129
orders. The proof follows the ususal pattern: *}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   130
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   131
instance parord < strord
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   132
apply intro_classes;
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   133
apply(simp_all (no_asm_use) add:less_le);
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   134
  apply(blast intro: trans antisym);
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   135
 apply(blast intro: refl);
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   136
done
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   137
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   138
text{*\noindent
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   139
The result is the following subclass diagram:
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   140
\[
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   141
\begin{array}{c}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   142
\isa{term}\\
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   143
|\\
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   144
\isa{ordrel}\\
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   145
|\\
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   146
\isa{strord}\\
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   147
|\\
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   148
\isa{parord}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   149
\end{array}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   150
\]
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   151
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   152
In general, the subclass diagram must be acyclic. Therefore Isabelle will
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   153
complain if you also prove the relationship @{text"strord < parord"}.
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   154
Multiple inheritance is however permitted.
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   155
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   156
This finishes our demonstration of type classes based on orderings.  We
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   157
remind our readers that \isa{Main} contains a much more developed theory of
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   158
orderings phrased in terms of the usual @{text"\<le>"} and @{text"<"}.
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   159
It is recommended that, if possible,
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   160
you base your own ordering relations on this theory.
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   161
*}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   162
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   163
(*
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   164
instance strord < parord
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   165
apply intro_classes;
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   166
apply(simp_all (no_asm_use) add:le_less);
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   167
apply(blast intro: less_trans);
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   168
apply(erule disjE);
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   169
apply(erule disjE);
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   170
apply(rule irrefl[THEN notE]);
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   171
apply(rule less_trans, assumption, assumption);
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   172
apply blast;apply blast;
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   173
apply(blast intro: irrefl[THEN notE]);
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   174
done
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   175
*)
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   176
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   177
subsubsection{*Inconsistencies*}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   178
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   179
text{* The reader may be wondering what happens if we, maybe accidentally,
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   180
attach an inconsistent set of axioms to a class. So far we have always
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   181
avoided to add new axioms to HOL for fear of inconsistencies and suddenly it
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   182
seems that we are throwing all caution to the wind. So why is there no
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   183
problem?
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   184
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   185
The point is that by construction, all type variables in the axioms of an
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   186
\isacommand{axclass} are automatically constrained with the class being
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   187
defined (as shown for axiom @{thm[source]refl} above). These constraints are
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   188
always carried around and Isabelle takes care that they are never lost,
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   189
unless the type variable is instantiated with a type that has been shown to
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   190
belong to that class. Thus you may be able to prove @{prop False}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   191
from your axioms, but Isabelle will remind you that this
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   192
theorem has the hidden hypothesis that the class is non-empty.
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   193
*}
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   194
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   195
(*
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   196
axclass false<"term"
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   197
false: "x \<noteq> x";
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   198
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   199
lemma "False";
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   200
by(rule notE[OF false HOL.refl]);
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   201
*)
bf33cbd76c05 *** empty log message ***
nipkow
parents:
diff changeset
   202
(*<*)end(*>*)