1 |
1 |
2 header {* Basic group theory *}; |
2 header {* Basic group theory *} |
3 |
3 |
4 theory Group = Main:; |
4 theory Group = Main: |
5 |
5 |
6 text {* |
6 text {* |
7 \medskip\noindent The meta-type system of Isabelle supports |
7 \medskip\noindent The meta-type system of Isabelle supports |
8 \emph{intersections} and \emph{inclusions} of type classes. These |
8 \emph{intersections} and \emph{inclusions} of type classes. These |
9 directly correspond to intersections and inclusions of type |
9 directly correspond to intersections and inclusions of type |
10 predicates in a purely set theoretic sense. This is sufficient as a |
10 predicates in a purely set theoretic sense. This is sufficient as a |
11 means to describe simple hierarchies of structures. As an |
11 means to describe simple hierarchies of structures. As an |
12 illustration, we use the well-known example of semigroups, monoids, |
12 illustration, we use the well-known example of semigroups, monoids, |
13 general groups and Abelian groups. |
13 general groups and Abelian groups. |
14 *}; |
14 *} |
15 |
15 |
16 subsection {* Monoids and Groups *}; |
16 subsection {* Monoids and Groups *} |
17 |
17 |
18 text {* |
18 text {* |
19 First we declare some polymorphic constants required later for the |
19 First we declare some polymorphic constants required later for the |
20 signature parts of our structures. |
20 signature parts of our structures. |
21 *}; |
21 *} |
22 |
22 |
23 consts |
23 consts |
24 times :: "'a => 'a => 'a" (infixl "\<Otimes>" 70) |
24 times :: "'a => 'a => 'a" (infixl "\<Otimes>" 70) |
25 inverse :: "'a => 'a" ("(_\<inv>)" [1000] 999) |
25 inverse :: "'a => 'a" ("(_\<inv>)" [1000] 999) |
26 one :: 'a ("\<unit>"); |
26 one :: 'a ("\<unit>") |
27 |
27 |
28 text {* |
28 text {* |
29 \noindent Next we define class $monoid$ of monoids with operations |
29 \noindent Next we define class $monoid$ of monoids with operations |
30 $\TIMES$ and $1$. Note that multiple class axioms are allowed for |
30 $\TIMES$ and $1$. Note that multiple class axioms are allowed for |
31 user convenience --- they simply represent the conjunction of their |
31 user convenience --- they simply represent the conjunction of their |
32 respective universal closures. |
32 respective universal closures. |
33 *}; |
33 *} |
34 |
34 |
35 axclass |
35 axclass |
36 monoid < "term" |
36 monoid < "term" |
37 assoc: "(x \<Otimes> y) \<Otimes> z = x \<Otimes> (y \<Otimes> z)" |
37 assoc: "(x \<Otimes> y) \<Otimes> z = x \<Otimes> (y \<Otimes> z)" |
38 left_unit: "\<unit> \<Otimes> x = x" |
38 left_unit: "\<unit> \<Otimes> x = x" |
39 right_unit: "x \<Otimes> \<unit> = x"; |
39 right_unit: "x \<Otimes> \<unit> = x" |
40 |
40 |
41 text {* |
41 text {* |
42 \noindent So class $monoid$ contains exactly those types $\tau$ where |
42 \noindent So class $monoid$ contains exactly those types $\tau$ where |
43 $\TIMES :: \tau \To \tau \To \tau$ and $1 :: \tau$ are specified |
43 $\TIMES :: \tau \To \tau \To \tau$ and $1 :: \tau$ are specified |
44 appropriately, such that $\TIMES$ is associative and $1$ is a left |
44 appropriately, such that $\TIMES$ is associative and $1$ is a left |
45 and right unit element for $\TIMES$. |
45 and right unit element for $\TIMES$. |
46 *}; |
46 *} |
47 |
47 |
48 text {* |
48 text {* |
49 \medskip Independently of $monoid$, we now define a linear hierarchy |
49 \medskip Independently of $monoid$, we now define a linear hierarchy |
50 of semigroups, general groups and Abelian groups. Note that the |
50 of semigroups, general groups and Abelian groups. Note that the |
51 names of class axioms are automatically qualified with each class |
51 names of class axioms are automatically qualified with each class |
52 name, so we may re-use common names such as $assoc$. |
52 name, so we may re-use common names such as $assoc$. |
53 *}; |
53 *} |
54 |
54 |
55 axclass |
55 axclass |
56 semigroup < "term" |
56 semigroup < "term" |
57 assoc: "(x \<Otimes> y) \<Otimes> z = x \<Otimes> (y \<Otimes> z)"; |
57 assoc: "(x \<Otimes> y) \<Otimes> z = x \<Otimes> (y \<Otimes> z)" |
58 |
58 |
59 axclass |
59 axclass |
60 group < semigroup |
60 group < semigroup |
61 left_unit: "\<unit> \<Otimes> x = x" |
61 left_unit: "\<unit> \<Otimes> x = x" |
62 left_inverse: "x\<inv> \<Otimes> x = \<unit>"; |
62 left_inverse: "x\<inv> \<Otimes> x = \<unit>" |
63 |
63 |
64 axclass |
64 axclass |
65 agroup < group |
65 agroup < group |
66 commute: "x \<Otimes> y = y \<Otimes> x"; |
66 commute: "x \<Otimes> y = y \<Otimes> x" |
67 |
67 |
68 text {* |
68 text {* |
69 \noindent Class $group$ inherits associativity of $\TIMES$ from |
69 \noindent Class $group$ inherits associativity of $\TIMES$ from |
70 $semigroup$ and adds two further group axioms. Similarly, $agroup$ |
70 $semigroup$ and adds two further group axioms. Similarly, $agroup$ |
71 is defined as the subset of $group$ such that for all of its elements |
71 is defined as the subset of $group$ such that for all of its elements |
72 $\tau$, the operation $\TIMES :: \tau \To \tau \To \tau$ is even |
72 $\tau$, the operation $\TIMES :: \tau \To \tau \To \tau$ is even |
73 commutative. |
73 commutative. |
74 *}; |
74 *} |
75 |
75 |
76 |
76 |
77 subsection {* Abstract reasoning *}; |
77 subsection {* Abstract reasoning *} |
78 |
78 |
79 text {* |
79 text {* |
80 In a sense, axiomatic type classes may be viewed as \emph{abstract |
80 In a sense, axiomatic type classes may be viewed as \emph{abstract |
81 theories}. Above class definitions gives rise to abstract axioms |
81 theories}. Above class definitions gives rise to abstract axioms |
82 $assoc$, $left_unit$, $left_inverse$, $commute$, where any of these |
82 $assoc$, $left_unit$, $left_inverse$, $commute$, where any of these |
90 \medskip From a technical point of view, abstract axioms are just |
90 \medskip From a technical point of view, abstract axioms are just |
91 ordinary Isabelle theorems, which may be used in proofs without |
91 ordinary Isabelle theorems, which may be used in proofs without |
92 special treatment. Such ``abstract proofs'' usually yield new |
92 special treatment. Such ``abstract proofs'' usually yield new |
93 ``abstract theorems''. For example, we may now derive the following |
93 ``abstract theorems''. For example, we may now derive the following |
94 well-known laws of general groups. |
94 well-known laws of general groups. |
95 *}; |
95 *} |
96 |
96 |
97 theorem group_right_inverse: "x \<Otimes> x\<inv> = (\<unit>\\<Colon>'a\\<Colon>group)"; |
97 theorem group_right_inverse: "x \<Otimes> x\<inv> = (\<unit>\\<Colon>'a\\<Colon>group)" |
98 proof -; |
98 proof - |
99 have "x \<Otimes> x\<inv> = \<unit> \<Otimes> (x \<Otimes> x\<inv>)"; |
99 have "x \<Otimes> x\<inv> = \<unit> \<Otimes> (x \<Otimes> x\<inv>)" |
100 by (simp only: group.left_unit); |
100 by (simp only: group.left_unit) |
101 also; have "... = \<unit> \<Otimes> x \<Otimes> x\<inv>"; |
101 also have "... = \<unit> \<Otimes> x \<Otimes> x\<inv>" |
102 by (simp only: semigroup.assoc); |
102 by (simp only: semigroup.assoc) |
103 also; have "... = (x\<inv>)\<inv> \<Otimes> x\<inv> \<Otimes> x \<Otimes> x\<inv>"; |
103 also have "... = (x\<inv>)\<inv> \<Otimes> x\<inv> \<Otimes> x \<Otimes> x\<inv>" |
104 by (simp only: group.left_inverse); |
104 by (simp only: group.left_inverse) |
105 also; have "... = (x\<inv>)\<inv> \<Otimes> (x\<inv> \<Otimes> x) \<Otimes> x\<inv>"; |
105 also have "... = (x\<inv>)\<inv> \<Otimes> (x\<inv> \<Otimes> x) \<Otimes> x\<inv>" |
106 by (simp only: semigroup.assoc); |
106 by (simp only: semigroup.assoc) |
107 also; have "... = (x\<inv>)\<inv> \<Otimes> \<unit> \<Otimes> x\<inv>"; |
107 also have "... = (x\<inv>)\<inv> \<Otimes> \<unit> \<Otimes> x\<inv>" |
108 by (simp only: group.left_inverse); |
108 by (simp only: group.left_inverse) |
109 also; have "... = (x\<inv>)\<inv> \<Otimes> (\<unit> \<Otimes> x\<inv>)"; |
109 also have "... = (x\<inv>)\<inv> \<Otimes> (\<unit> \<Otimes> x\<inv>)" |
110 by (simp only: semigroup.assoc); |
110 by (simp only: semigroup.assoc) |
111 also; have "... = (x\<inv>)\<inv> \<Otimes> x\<inv>"; |
111 also have "... = (x\<inv>)\<inv> \<Otimes> x\<inv>" |
112 by (simp only: group.left_unit); |
112 by (simp only: group.left_unit) |
113 also; have "... = \<unit>"; |
113 also have "... = \<unit>" |
114 by (simp only: group.left_inverse); |
114 by (simp only: group.left_inverse) |
115 finally; show ?thesis; .; |
115 finally show ?thesis . |
116 qed; |
116 qed |
117 |
117 |
118 text {* |
118 text {* |
119 \noindent With $group_right_inverse$ already available, |
119 \noindent With $group_right_inverse$ already available, |
120 $group_right_unit$\label{thm:group-right-unit} is now established |
120 $group_right_unit$\label{thm:group-right-unit} is now established |
121 much easier. |
121 much easier. |
122 *}; |
122 *} |
123 |
123 |
124 theorem group_right_unit: "x \<Otimes> \<unit> = (x\\<Colon>'a\\<Colon>group)"; |
124 theorem group_right_unit: "x \<Otimes> \<unit> = (x\\<Colon>'a\\<Colon>group)" |
125 proof -; |
125 proof - |
126 have "x \<Otimes> \<unit> = x \<Otimes> (x\<inv> \<Otimes> x)"; |
126 have "x \<Otimes> \<unit> = x \<Otimes> (x\<inv> \<Otimes> x)" |
127 by (simp only: group.left_inverse); |
127 by (simp only: group.left_inverse) |
128 also; have "... = x \<Otimes> x\<inv> \<Otimes> x"; |
128 also have "... = x \<Otimes> x\<inv> \<Otimes> x" |
129 by (simp only: semigroup.assoc); |
129 by (simp only: semigroup.assoc) |
130 also; have "... = \<unit> \<Otimes> x"; |
130 also have "... = \<unit> \<Otimes> x" |
131 by (simp only: group_right_inverse); |
131 by (simp only: group_right_inverse) |
132 also; have "... = x"; |
132 also have "... = x" |
133 by (simp only: group.left_unit); |
133 by (simp only: group.left_unit) |
134 finally; show ?thesis; .; |
134 finally show ?thesis . |
135 qed; |
135 qed |
136 |
136 |
137 text {* |
137 text {* |
138 \medskip Abstract theorems may be instantiated to only those types |
138 \medskip Abstract theorems may be instantiated to only those types |
139 $\tau$ where the appropriate class membership $\tau :: c$ is known at |
139 $\tau$ where the appropriate class membership $\tau :: c$ is known at |
140 Isabelle's type signature level. Since we have $agroup \subseteq |
140 Isabelle's type signature level. Since we have $agroup \subseteq |
141 group \subseteq semigroup$ by definition, all theorems of $semigroup$ |
141 group \subseteq semigroup$ by definition, all theorems of $semigroup$ |
142 and $group$ are automatically inherited by $group$ and $agroup$. |
142 and $group$ are automatically inherited by $group$ and $agroup$. |
143 *}; |
143 *} |
144 |
144 |
145 |
145 |
146 subsection {* Abstract instantiation *}; |
146 subsection {* Abstract instantiation *} |
147 |
147 |
148 text {* |
148 text {* |
149 From the definition, the $monoid$ and $group$ classes have been |
149 From the definition, the $monoid$ and $group$ classes have been |
150 independent. Note that for monoids, $right_unit$ had to be included |
150 independent. Note that for monoids, $right_unit$ had to be included |
151 as an axiom, but for groups both $right_unit$ and $right_inverse$ are |
151 as an axiom, but for groups both $right_unit$ and $right_inverse$ are |
179 \end{picture} |
179 \end{picture} |
180 \caption{Monoids and groups: according to definition, and by proof} |
180 \caption{Monoids and groups: according to definition, and by proof} |
181 \label{fig:monoid-group} |
181 \label{fig:monoid-group} |
182 \end{center} |
182 \end{center} |
183 \end{figure} |
183 \end{figure} |
184 *}; |
184 *} |
185 |
185 |
186 instance monoid < semigroup; |
186 instance monoid < semigroup |
187 proof intro_classes; |
187 proof intro_classes |
188 fix x y z :: "'a\\<Colon>monoid"; |
188 fix x y z :: "'a\\<Colon>monoid" |
189 show "x \<Otimes> y \<Otimes> z = x \<Otimes> (y \<Otimes> z)"; |
189 show "x \<Otimes> y \<Otimes> z = x \<Otimes> (y \<Otimes> z)" |
190 by (rule monoid.assoc); |
190 by (rule monoid.assoc) |
191 qed; |
191 qed |
192 |
192 |
193 instance group < monoid; |
193 instance group < monoid |
194 proof intro_classes; |
194 proof intro_classes |
195 fix x y z :: "'a\\<Colon>group"; |
195 fix x y z :: "'a\\<Colon>group" |
196 show "x \<Otimes> y \<Otimes> z = x \<Otimes> (y \<Otimes> z)"; |
196 show "x \<Otimes> y \<Otimes> z = x \<Otimes> (y \<Otimes> z)" |
197 by (rule semigroup.assoc); |
197 by (rule semigroup.assoc) |
198 show "\<unit> \<Otimes> x = x"; |
198 show "\<unit> \<Otimes> x = x" |
199 by (rule group.left_unit); |
199 by (rule group.left_unit) |
200 show "x \<Otimes> \<unit> = x"; |
200 show "x \<Otimes> \<unit> = x" |
201 by (rule group_right_unit); |
201 by (rule group_right_unit) |
202 qed; |
202 qed |
203 |
203 |
204 text {* |
204 text {* |
205 \medskip The $\isakeyword{instance}$ command sets up an appropriate |
205 \medskip The $\isakeyword{instance}$ command sets up an appropriate |
206 goal that represents the class inclusion (or type arity, see |
206 goal that represents the class inclusion (or type arity, see |
207 \secref{sec:inst-arity}) to be proven |
207 \secref{sec:inst-arity}) to be proven |
209 method does back-chaining of class membership statements wrt.\ the |
209 method does back-chaining of class membership statements wrt.\ the |
210 hierarchy of any classes defined in the current theory; the effect is |
210 hierarchy of any classes defined in the current theory; the effect is |
211 to reduce to the initial statement to a number of goals that directly |
211 to reduce to the initial statement to a number of goals that directly |
212 correspond to any class axioms encountered on the path upwards |
212 correspond to any class axioms encountered on the path upwards |
213 through the class hierarchy. |
213 through the class hierarchy. |
214 *}; |
214 *} |
215 |
215 |
216 |
216 |
217 subsection {* Concrete instantiation \label{sec:inst-arity} *}; |
217 subsection {* Concrete instantiation \label{sec:inst-arity} *} |
218 |
218 |
219 text {* |
219 text {* |
220 So far we have covered the case of the form |
220 So far we have covered the case of the form |
221 $\isakeyword{instance}~c@1 < c@2$, namely \emph{abstract |
221 $\isakeyword{instance}~c@1 < c@2$, namely \emph{abstract |
222 instantiation} --- $c@1$ is more special than $c@2$ and thus an |
222 instantiation} --- $c@1$ is more special than $c@2$ and thus an |
227 transferred to Isabelle's type signature level. |
227 transferred to Isabelle's type signature level. |
228 |
228 |
229 \medskip As a typical example, we show that type $bool$ with |
229 \medskip As a typical example, we show that type $bool$ with |
230 exclusive-or as operation $\TIMES$, identity as $\isasyminv$, and |
230 exclusive-or as operation $\TIMES$, identity as $\isasyminv$, and |
231 $False$ as $1$ forms an Abelian group. |
231 $False$ as $1$ forms an Abelian group. |
232 *}; |
232 *} |
233 |
233 |
234 defs |
234 defs |
235 times_bool_def: "x \<Otimes> y \\<equiv> x \\<noteq> (y\\<Colon>bool)" |
235 times_bool_def: "x \<Otimes> y \\<equiv> x \\<noteq> (y\\<Colon>bool)" |
236 inverse_bool_def: "x\<inv> \\<equiv> x\\<Colon>bool" |
236 inverse_bool_def: "x\<inv> \\<equiv> x\\<Colon>bool" |
237 unit_bool_def: "\<unit> \\<equiv> False"; |
237 unit_bool_def: "\<unit> \\<equiv> False" |
238 |
238 |
239 text {* |
239 text {* |
240 \medskip It is important to note that above $\DEFS$ are just |
240 \medskip It is important to note that above $\DEFS$ are just |
241 overloaded meta-level constant definitions, where type classes are |
241 overloaded meta-level constant definitions, where type classes are |
242 not yet involved at all. This form of constant definition with |
242 not yet involved at all. This form of constant definition with |
247 best applied in the context of type classes. |
247 best applied in the context of type classes. |
248 |
248 |
249 \medskip Since we have chosen above $\DEFS$ of the generic group |
249 \medskip Since we have chosen above $\DEFS$ of the generic group |
250 operations on type $bool$ appropriately, the class membership $bool |
250 operations on type $bool$ appropriately, the class membership $bool |
251 :: agroup$ may be now derived as follows. |
251 :: agroup$ may be now derived as follows. |
252 *}; |
252 *} |
253 |
253 |
254 instance bool :: agroup; |
254 instance bool :: agroup |
255 proof (intro_classes, |
255 proof (intro_classes, |
256 unfold times_bool_def inverse_bool_def unit_bool_def); |
256 unfold times_bool_def inverse_bool_def unit_bool_def) |
257 fix x y z; |
257 fix x y z |
258 show "((x \\<noteq> y) \\<noteq> z) = (x \\<noteq> (y \\<noteq> z))"; by blast; |
258 show "((x \\<noteq> y) \\<noteq> z) = (x \\<noteq> (y \\<noteq> z))" by blast |
259 show "(False \\<noteq> x) = x"; by blast; |
259 show "(False \\<noteq> x) = x" by blast |
260 show "(x \\<noteq> x) = False"; by blast; |
260 show "(x \\<noteq> x) = False" by blast |
261 show "(x \\<noteq> y) = (y \\<noteq> x)"; by blast; |
261 show "(x \\<noteq> y) = (y \\<noteq> x)" by blast |
262 qed; |
262 qed |
263 |
263 |
264 text {* |
264 text {* |
265 The result of an $\isakeyword{instance}$ statement is both expressed |
265 The result of an $\isakeyword{instance}$ statement is both expressed |
266 as a theorem of Isabelle's meta-logic, and as a type arity of the |
266 as a theorem of Isabelle's meta-logic, and as a type arity of the |
267 type signature. The latter enables type-inference system to take |
267 type signature. The latter enables type-inference system to take |
272 defining $\TIMES$ as addition, $\isasyminv$ as negation and $1$ as |
272 defining $\TIMES$ as addition, $\isasyminv$ as negation and $1$ as |
273 zero) or $list :: (term)semigroup$ (e.g.\ if $\TIMES$ is defined as |
273 zero) or $list :: (term)semigroup$ (e.g.\ if $\TIMES$ is defined as |
274 list append). Thus, the characteristic constants $\TIMES$, |
274 list append). Thus, the characteristic constants $\TIMES$, |
275 $\isasyminv$, $1$ really become overloaded, i.e.\ have different |
275 $\isasyminv$, $1$ really become overloaded, i.e.\ have different |
276 meanings on different types. |
276 meanings on different types. |
277 *}; |
277 *} |
278 |
278 |
279 |
279 |
280 subsection {* Lifting and Functors *}; |
280 subsection {* Lifting and Functors *} |
281 |
281 |
282 text {* |
282 text {* |
283 As already mentioned above, overloading in the simply-typed HOL |
283 As already mentioned above, overloading in the simply-typed HOL |
284 systems may include recursion over the syntactic structure of types. |
284 systems may include recursion over the syntactic structure of types. |
285 That is, definitional equations $c^\tau \equiv t$ may also contain |
285 That is, definitional equations $c^\tau \equiv t$ may also contain |
287 that are structurally simpler than $\tau$. |
287 that are structurally simpler than $\tau$. |
288 |
288 |
289 This feature enables us to \emph{lift operations}, say to Cartesian |
289 This feature enables us to \emph{lift operations}, say to Cartesian |
290 products, direct sums or function spaces. Subsequently we lift |
290 products, direct sums or function spaces. Subsequently we lift |
291 $\TIMES$ component-wise to binary products $\alpha \times \beta$. |
291 $\TIMES$ component-wise to binary products $\alpha \times \beta$. |
292 *}; |
292 *} |
293 |
293 |
294 defs |
294 defs |
295 times_prod_def: "p \<Otimes> q \\<equiv> (fst p \<Otimes> fst q, snd p \<Otimes> snd q)"; |
295 times_prod_def: "p \<Otimes> q \\<equiv> (fst p \<Otimes> fst q, snd p \<Otimes> snd q)" |
296 |
296 |
297 text {* |
297 text {* |
298 It is very easy to see that associativity of $\TIMES^\alpha$ and |
298 It is very easy to see that associativity of $\TIMES^\alpha$ and |
299 $\TIMES^\beta$ transfers to ${\TIMES}^{\alpha \times \beta}$. Hence |
299 $\TIMES^\beta$ transfers to ${\TIMES}^{\alpha \times \beta}$. Hence |
300 the binary type constructor $\times$ maps semigroups to semigroups. |
300 the binary type constructor $\times$ maps semigroups to semigroups. |
301 This may be established formally as follows. |
301 This may be established formally as follows. |
302 *}; |
302 *} |
303 |
303 |
304 instance * :: (semigroup, semigroup) semigroup; |
304 instance * :: (semigroup, semigroup) semigroup |
305 proof (intro_classes, unfold times_prod_def); |
305 proof (intro_classes, unfold times_prod_def) |
306 fix p q r :: "'a\\<Colon>semigroup \\<times> 'b\\<Colon>semigroup"; |
306 fix p q r :: "'a\\<Colon>semigroup \\<times> 'b\\<Colon>semigroup" |
307 show |
307 show |
308 "(fst (fst p \<Otimes> fst q, snd p \<Otimes> snd q) \<Otimes> fst r, |
308 "(fst (fst p \<Otimes> fst q, snd p \<Otimes> snd q) \<Otimes> fst r, |
309 snd (fst p \<Otimes> fst q, snd p \<Otimes> snd q) \<Otimes> snd r) = |
309 snd (fst p \<Otimes> fst q, snd p \<Otimes> snd q) \<Otimes> snd r) = |
310 (fst p \<Otimes> fst (fst q \<Otimes> fst r, snd q \<Otimes> snd r), |
310 (fst p \<Otimes> fst (fst q \<Otimes> fst r, snd q \<Otimes> snd r), |
311 snd p \<Otimes> snd (fst q \<Otimes> fst r, snd q \<Otimes> snd r))"; |
311 snd p \<Otimes> snd (fst q \<Otimes> fst r, snd q \<Otimes> snd r))" |
312 by (simp add: semigroup.assoc); |
312 by (simp add: semigroup.assoc) |
313 qed; |
313 qed |
314 |
314 |
315 text {* |
315 text {* |
316 Thus, if we view class instances as ``structures'', then overloaded |
316 Thus, if we view class instances as ``structures'', then overloaded |
317 constant definitions with recursion over types indirectly provide |
317 constant definitions with recursion over types indirectly provide |
318 some kind of ``functors'' --- i.e.\ mappings between abstract |
318 some kind of ``functors'' --- i.e.\ mappings between abstract |
319 theories. |
319 theories. |
320 *}; |
320 *} |
321 |
321 |
322 end; |
322 end |