14 |
14 |
15 abbreviation |
15 abbreviation |
16 "Append_rexp2 r_itm r \<equiv> Append_rexp r r_itm" |
16 "Append_rexp2 r_itm r \<equiv> Append_rexp r r_itm" |
17 |
17 |
18 |
18 |
|
19 abbreviation |
|
20 "pow" (infixl "\<up>" 100) |
|
21 where |
|
22 "A \<up> n \<equiv> A ^^ n" |
|
23 |
|
24 syntax (latex output) |
|
25 "_Collect" :: "pttrn => bool => 'a set" ("(1{_ | _})") |
|
26 "_CollectIn" :: "pttrn => 'a set => bool => 'a set" ("(1{_ \<in> _ | _})") |
|
27 translations |
|
28 "_Collect p P" <= "{p. P}" |
|
29 "_Collect p P" <= "{p|xs. P}" |
|
30 "_CollectIn p A P" <= "{p : A. P}" |
|
31 |
|
32 abbreviation "NULL \<equiv> Zero" |
|
33 abbreviation "EMPTY \<equiv> One" |
|
34 abbreviation "CHAR \<equiv> Atom" |
|
35 abbreviation "ALT \<equiv> Plus" |
|
36 abbreviation "SEQ \<equiv> Times" |
|
37 abbreviation "STAR \<equiv> Star" |
|
38 |
|
39 |
|
40 ML {* @{term "op ^^"} *} |
|
41 |
19 notation (latex output) |
42 notation (latex output) |
20 str_eq_rel ("\<approx>\<^bsub>_\<^esub>") and |
43 str_eq_rel ("\<approx>\<^bsub>_\<^esub>") and |
21 str_eq ("_ \<approx>\<^bsub>_\<^esub> _") and |
44 str_eq ("_ \<approx>\<^bsub>_\<^esub> _") and |
22 Seq (infixr "\<cdot>" 100) and |
45 conc (infixr "\<cdot>" 100) and |
23 Star ("_\<^bsup>\<star>\<^esup>") and |
46 star ("_\<^bsup>\<star>\<^esup>") and |
24 pow ("_\<^bsup>_\<^esup>" [100, 100] 100) and |
47 pow ("_\<^bsup>_\<^esup>" [100, 100] 100) and |
25 Suc ("_+1" [100] 100) and |
48 Suc ("_+1" [100] 100) and |
26 quotient ("_ \<^raw:\ensuremath{\!\sslash\!}> _" [90, 90] 90) and |
49 quotient ("_ \<^raw:\ensuremath{\!\sslash\!}> _" [90, 90] 90) and |
27 REL ("\<approx>") and |
50 REL ("\<approx>") and |
28 UPLUS ("_ \<^raw:\ensuremath{\uplus}> _" [90, 90] 90) and |
51 UPLUS ("_ \<^raw:\ensuremath{\uplus}> _" [90, 90] 90) and |
29 L_rexp ("\<^raw:\ensuremath{\cal{L}}>'(_')" [0] 101) and |
52 lang ("\<^raw:\ensuremath{\cal{L}}>'(_')" [0] 101) and |
30 Lam ("\<lambda>'(_')" [100] 100) and |
53 Lam ("\<lambda>'(_')" [100] 100) and |
31 Trn ("'(_, _')" [100, 100] 100) and |
54 Trn ("'(_, _')" [100, 100] 100) and |
32 EClass ("\<lbrakk>_\<rbrakk>\<^bsub>_\<^esub>" [100, 100] 100) and |
55 EClass ("\<lbrakk>_\<rbrakk>\<^bsub>_\<^esub>" [100, 100] 100) and |
33 transition ("_ \<^raw:\ensuremath{\stackrel{\text{>_\<^raw:}}{\Longmapsto}}> _" [100, 100, 100] 100) and |
56 transition ("_ \<^raw:\ensuremath{\stackrel{\text{>_\<^raw:}}{\Longmapsto}}> _" [100, 100, 100] 100) and |
34 Setalt ("\<^raw:\ensuremath{\bigplus}>_" [1000] 999) and |
57 Setalt ("\<^raw:\ensuremath{\bigplus}>_" [1000] 999) and |
35 Append_rexp2 ("_ \<^raw:\ensuremath{\triangleleft}> _" [100, 100] 100) and |
58 Append_rexp2 ("_ \<^raw:\ensuremath{\triangleleft}> _" [100, 100] 100) and |
36 Append_rexp_rhs ("_ \<^raw:\ensuremath{\triangleleft}> _" [100, 100] 50) and |
59 Append_rexp_rhs ("_ \<^raw:\ensuremath{\triangleleft}> _" [100, 100] 50) and |
|
60 |
37 uminus ("\<^raw:\ensuremath{\overline{>_\<^raw:}}>" [100] 100) and |
61 uminus ("\<^raw:\ensuremath{\overline{>_\<^raw:}}>" [100] 100) and |
38 tag_str_ALT ("tag\<^isub>A\<^isub>L\<^isub>T _ _" [100, 100] 100) and |
62 tag_str_Plus ("tag\<^isub>A\<^isub>L\<^isub>T _ _" [100, 100] 100) and |
39 tag_str_ALT ("tag\<^isub>A\<^isub>L\<^isub>T _ _ _" [100, 100, 100] 100) and |
63 tag_str_Plus ("tag\<^isub>A\<^isub>L\<^isub>T _ _ _" [100, 100, 100] 100) and |
40 tag_str_SEQ ("tag\<^isub>S\<^isub>E\<^isub>Q _ _" [100, 100] 100) and |
64 tag_str_Times ("tag\<^isub>S\<^isub>E\<^isub>Q _ _" [100, 100] 100) and |
41 tag_str_SEQ ("tag\<^isub>S\<^isub>E\<^isub>Q _ _ _" [100, 100, 100] 100) and |
65 tag_str_Times ("tag\<^isub>S\<^isub>E\<^isub>Q _ _ _" [100, 100, 100] 100) and |
42 tag_str_STAR ("tag\<^isub>S\<^isub>T\<^isub>A\<^isub>R _" [100] 100) and |
66 tag_str_Star ("tag\<^isub>S\<^isub>T\<^isub>A\<^isub>R _" [100] 100) and |
43 tag_str_STAR ("tag\<^isub>S\<^isub>T\<^isub>A\<^isub>R _ _" [100, 100] 100) |
67 tag_str_Star ("tag\<^isub>S\<^isub>T\<^isub>A\<^isub>R _ _" [100, 100] 100) |
44 |
68 |
45 lemma meta_eq_app: |
69 lemma meta_eq_app: |
46 shows "f \<equiv> \<lambda>x. g x \<Longrightarrow> f x \<equiv> g x" |
70 shows "f \<equiv> \<lambda>x. g x \<Longrightarrow> f x \<equiv> g x" |
47 by auto |
71 by auto |
|
72 |
|
73 lemma conc_def': |
|
74 "A \<cdot> B = {s\<^isub>1 @ s\<^isub>2 | s\<^isub>1 s\<^isub>2. s\<^isub>1 \<in> A \<and> s\<^isub>2 \<in> B}" |
|
75 unfolding conc_def by simp |
|
76 |
|
77 lemma conc_Union_left: |
|
78 shows "B \<cdot> (\<Union>n. A \<up> n) = (\<Union>n. B \<cdot> (A \<up> n))" |
|
79 unfolding conc_def by auto |
|
80 |
|
81 lemma test: |
|
82 assumes X_in_eqs: "(X, rhs) \<in> Init (UNIV // \<approx>A)" |
|
83 shows "X = \<Union> (lang_trm ` rhs)" |
|
84 using assms l_eq_r_in_eqs by (simp) |
|
85 |
48 |
86 |
49 (* THEOREMS *) |
87 (* THEOREMS *) |
50 |
88 |
51 notation (Rule output) |
89 notation (Rule output) |
52 "==>" ("\<^raw:\mbox{}\inferrule{\mbox{>_\<^raw:}}>\<^raw:{\mbox{>_\<^raw:}}>") |
90 "==>" ("\<^raw:\mbox{}\inferrule{\mbox{>_\<^raw:}}>\<^raw:{\mbox{>_\<^raw:}}>") |
89 \noindent |
127 \noindent |
90 Regular languages are an important and well-understood subject in Computer |
128 Regular languages are an important and well-understood subject in Computer |
91 Science, with many beautiful theorems and many useful algorithms. There is a |
129 Science, with many beautiful theorems and many useful algorithms. There is a |
92 wide range of textbooks on this subject, many of which are aimed at students |
130 wide range of textbooks on this subject, many of which are aimed at students |
93 and contain very detailed `pencil-and-paper' proofs |
131 and contain very detailed `pencil-and-paper' proofs |
94 (e.g.~\cite{Kozen97}). It seems natural to exercise theorem provers by |
132 (e.g.~\cite{Kozen97, HopcroftUllman69}). It seems natural to exercise theorem provers by |
95 formalising the theorems and by verifying formally the algorithms. |
133 formalising the theorems and by verifying formally the algorithms. A |
96 Some of the popular theorem provers are based on Higher-Order Logic (HOL). |
134 popular choice for a theorem prover would be one based on Higher-Order Logic |
97 |
135 (HOL), such as HOL4, HOLlight and Isabelle/HOL. For our development we will |
98 There is however a problem: the typical approach to regular languages is to |
136 use the latter theorem prover. One distinguishing feature of HOL is it's |
|
137 type system based on Church's Simple Theory of Types \cite{Church40}. The |
|
138 limitations of this type system are one of the main motivations |
|
139 behind the work presented in this paper. |
|
140 |
|
141 The typical approach to regular languages is to |
99 introduce finite automata and then define everything in terms of them. For |
142 introduce finite automata and then define everything in terms of them. For |
100 example, a regular language is normally defined as one whose strings are |
143 example, a regular language is normally defined as one whose strings are |
101 recognised by a finite deterministic automaton. This approach has many |
144 recognised by a finite deterministic automaton. This approach has many |
102 benefits. Among them is the fact that it is easy to convince oneself that |
145 benefits. Among them is the fact that it is easy to convince oneself that |
103 regular languages are closed under complementation: one just has to exchange |
146 regular languages are closed under complementation: one just has to exchange |
104 the accepting and non-accepting states in the corresponding automaton to |
147 the accepting and non-accepting states in the corresponding automaton to |
105 obtain an automaton for the complement language. The problem, however, lies with |
148 obtain an automaton for the complement language. The problem, however, lies |
106 formalising such reasoning in a HOL-based theorem prover, in our case |
149 with formalising such reasoning in a HOL-based theorem prover. Automata are |
107 Isabelle/HOL. Automata are built up from states and transitions that |
150 built up from states and transitions that need to be represented as graphs, |
108 need to be represented as graphs, matrices or functions, none |
151 matrices or functions, none of which can be defined as an inductive |
109 of which can be defined as an inductive datatype. |
152 datatype. |
110 |
153 |
111 In case of graphs and matrices, this means we have to build our own |
154 In case of graphs and matrices, this means we have to build our own |
112 reasoning infrastructure for them, as neither Isabelle/HOL nor HOL4 nor |
155 reasoning infrastructure for them, as neither Isabelle/HOL nor HOL4 nor |
113 HOLlight support them with libraries. Even worse, reasoning about graphs and |
156 HOLlight support them with libraries. Even worse, reasoning about graphs and |
114 matrices can be a real hassle in HOL-based theorem provers. Consider for |
157 matrices can be a real hassle in HOL-based theorem provers, because |
|
158 we have to be able to combine automata. Consider for |
115 example the operation of sequencing two automata, say $A_1$ and $A_2$, by |
159 example the operation of sequencing two automata, say $A_1$ and $A_2$, by |
116 connecting the accepting states of $A_1$ to the initial state of $A_2$: |
160 connecting the accepting states of $A_1$ to the initial state of $A_2$: |
117 % |
161 % |
|
162 |
118 \begin{center} |
163 \begin{center} |
119 \begin{tabular}{ccc} |
164 \begin{tabular}{ccc} |
120 \begin{tikzpicture}[scale=0.8] |
165 \begin{tikzpicture}[scale=0.9] |
121 %\draw[step=2mm] (-1,-1) grid (1,1); |
166 %\draw[step=2mm] (-1,-1) grid (1,1); |
122 |
167 |
123 \draw[rounded corners=1mm, very thick] (-1.0,-0.3) rectangle (-0.2,0.3); |
168 \draw[rounded corners=1mm, very thick] (-1.0,-0.3) rectangle (-0.2,0.3); |
124 \draw[rounded corners=1mm, very thick] ( 0.2,-0.3) rectangle ( 1.0,0.3); |
169 \draw[rounded corners=1mm, very thick] ( 0.2,-0.3) rectangle ( 1.0,0.3); |
125 |
170 |
168 |
213 |
169 \end{tabular} |
214 \end{tabular} |
170 \end{center} |
215 \end{center} |
171 |
216 |
172 \noindent |
217 \noindent |
173 On `paper' we can define the corresponding graph in terms of the disjoint |
218 On `paper' or a theorem prover based on set-theory, we can define the corresponding |
|
219 graph in terms of the disjoint |
174 union of the state nodes. Unfortunately in HOL, the standard definition for disjoint |
220 union of the state nodes. Unfortunately in HOL, the standard definition for disjoint |
175 union, namely |
221 union, namely |
176 % |
222 % |
177 \begin{equation}\label{disjointunion} |
223 \begin{equation}\label{disjointunion} |
178 @{term "UPLUS A\<^isub>1 A\<^isub>2 \<equiv> {(1, x) | x. x \<in> A\<^isub>1} \<union> {(2, y) | y. y \<in> A\<^isub>2}"} |
224 @{text "A\<^isub>1 \<uplus> A\<^isub>2 \<equiv> {(1, x) | x \<in> A\<^isub>1} \<union> {(2, y) | y \<in> A\<^isub>2}"} |
179 \end{equation} |
225 \end{equation} |
180 |
226 |
181 \noindent |
227 \noindent |
182 changes the type---the disjoint union is not a set, but a set of pairs. |
228 changes the type---the disjoint union is not a set, but a set of pairs. |
183 Using this definition for disjoint union means we do not have a single type for automata |
229 Using this definition for disjoint union means we do not have a single type for automata |
184 and hence will not be able to state certain properties about \emph{all} |
230 and hence will not be able to state certain properties about \emph{all} |
185 automata, since there is no type quantification available in HOL (unlike in Coq, for example). An |
231 automata, since there is no type quantification available in HOL (unlike in Coq, for example). |
186 alternative, which provides us with a single type for automata, is to give every |
232 As a result, we would not be able to define a language being regular |
|
233 in terms of the existence of an automata. |
|
234 |
|
235 An alternative, which provides us with a single type for automata, is to give every |
187 state node an identity, for example a natural |
236 state node an identity, for example a natural |
188 number, and then be careful to rename these identities apart whenever |
237 number, and then be careful to rename these identities apart whenever |
189 connecting two automata. This results in clunky proofs |
238 connecting two automata. This results in clunky proofs |
190 establishing that properties are invariant under renaming. Similarly, |
239 establishing that properties are invariant under renaming. Similarly, |
191 connecting two automata represented as matrices results in very adhoc |
240 connecting two automata represented as matrices results in very adhoc |
217 \end{tabular} |
266 \end{tabular} |
218 \end{quote} |
267 \end{quote} |
219 |
268 |
220 |
269 |
221 \noindent |
270 \noindent |
222 Moreover, it is not so clear how to conveniently impose a finiteness condition |
271 Moreover, it is not so clear how to conveniently impose a finiteness |
223 upon functions in order to represent \emph{finite} automata. The best is |
272 condition upon functions in order to represent \emph{finite} automata. The |
224 probably to resort to more advanced reasoning frameworks, such as \emph{locales} |
273 best is probably to resort to more advanced reasoning frameworks, such as |
225 or \emph{type classes}, |
274 \emph{locales} or \emph{type classes}, which are \emph{not} available in all |
226 which are \emph{not} available in all HOL-based theorem provers. |
275 HOL-based theorem provers. |
227 |
276 |
228 {\bf add commnets from Brozowski} |
277 Because of these problems to do with representing automata, there seems to |
229 |
278 be no substantial formalisation of automata theory and regular languages |
230 Because of these problems to do with representing automata, there seems |
279 carried out in HOL-based theorem provers. Nipkow \cite{Nipkow98} establishes |
231 to be no substantial formalisation of automata theory and regular languages |
280 the link between regular expressions and automata in the context of |
232 carried out in HOL-based theorem provers. Nipkow \cite{Nipkow98} establishes |
281 lexing. Berghofer and Reiter \cite{BerghoferReiter09} formalise automata |
233 the link between regular expressions and automata in |
282 working over bit strings in the context of Presburger arithmetic. The only |
234 the context of lexing. Berghofer and Reiter \cite{BerghoferReiter09} |
283 larger formalisations of automata theory are carried out in Nuprl |
235 formalise automata working over |
284 \cite{Constable00} and in Coq \cite{Filliatre97}. |
236 bit strings in the context of Presburger arithmetic. |
285 |
237 The only larger formalisations of automata theory |
286 Also one might consider the Myhill-Nerode theorem as well-worn stock |
238 are carried out in Nuprl \cite{Constable00} and in Coq \cite{Filliatre97}. |
287 material for a computer scientists, but paper proofs of this theorem contain some |
|
288 subtle side-conditions which are easily overlooked and which make formal reasoning |
|
289 painful. For example in Kozen's proof \cite{Kozen97} it is not sufficient to |
|
290 have just any automata recognising a regular language, but one which does |
|
291 not have inaccessible states. This means if we define a regular language |
|
292 for which \emph{any} finite automaton exists, then one has to ensure that |
|
293 another equivalent can be found satisfying the side-conditions. Similarly |
|
294 Brozowski mentiones in \cite{Brozowski10} side-conditions of finite automata |
|
295 in connection of state-complexity: there it is required that automata |
|
296 must be complete in the sense of having a total transition function. |
|
297 Furthermore, if a `sink' state is present which accepts no word, then there |
|
298 must be only one such state. . . . |
|
299 Such 'little' lemmas make formalisation of these results in a theroem |
|
300 prover hair-pulling experiences. |
239 |
301 |
240 In this paper, we will not attempt to formalise automata theory in |
302 In this paper, we will not attempt to formalise automata theory in |
241 Isabelle/HOL, but take a different approach to regular |
303 Isabelle/HOL nor attempt to formalise any automata proof from the |
242 languages. Instead of defining a regular language as one where there exists |
304 literature, but take a different approach to regular languages than is |
243 an automaton that recognises all strings of the language, we define a |
305 usually taken. Instead of defining a regular language as one where there |
|
306 exists an automaton that recognises all strings of the language, we define a |
244 regular language as: |
307 regular language as: |
245 |
308 |
246 \begin{dfntn} |
309 \begin{dfntn} |
247 A language @{text A} is \emph{regular}, provided there is a regular expression that matches all |
310 A language @{text A} is \emph{regular}, provided there is a regular expression that matches all |
248 strings of @{text "A"}. |
311 strings of @{text "A"}. |
249 \end{dfntn} |
312 \end{dfntn} |
250 |
313 |
251 \noindent |
314 \noindent |
252 The reason is that regular expressions, unlike graphs, matrices and functions, can |
315 The reason is that regular expressions, unlike graphs, matrices and |
253 be easily defined as inductive datatype. Consequently a corresponding reasoning |
316 functions, can be easily defined as inductive datatype. Consequently a |
254 infrastructure comes for free. This has recently been exploited in HOL4 with a formalisation |
317 corresponding reasoning infrastructure (like induction or recursion) comes |
255 of regular expression matching based on derivatives \cite{OwensSlind08} and |
318 for free. This has recently been exploited in HOL4 with a formalisation of |
256 with an equivalence checker for regular expressions in Isabelle/HOL \cite{KraussNipkow11}. |
319 regular expression matching based on derivatives \cite{OwensSlind08} and |
257 The purpose of this paper is to |
320 with an equivalence checker for regular expressions in Isabelle/HOL |
258 show that a central result about regular languages---the Myhill-Nerode theorem---can |
321 \cite{KraussNipkow11}. The purpose of this paper is to show that a central |
259 be recreated by only using regular expressions. This theorem gives necessary |
322 result about regular languages---the Myhill-Nerode theorem---can be |
260 and sufficient conditions for when a language is regular. As a corollary of this |
323 recreated by only using regular expressions. This theorem gives necessary |
261 theorem we can easily establish the usual closure properties, including |
324 and sufficient conditions for when a language is regular. As a corollary of |
262 complementation, for regular languages.\smallskip |
325 this theorem we can easily establish the usual closure properties, including |
263 |
326 complementation, for regular languages.\medskip |
264 \noindent |
327 |
265 {\bf Contributions:} |
328 \noindent |
266 There is an extensive literature on regular languages. |
329 {\bf Contributions:} There is an extensive literature on regular languages. |
267 To our best knowledge, our proof of the Myhill-Nerode theorem is the |
330 To our best knowledge, our proof of the Myhill-Nerode theorem is the first |
268 first that is based on regular expressions, only. We prove the part of this theorem |
331 that is based on regular expressions, only. The part of this theorem stating |
269 stating that a regular expression has only finitely many partitions using certain |
332 that finitely many partitions of a language w.r.t.~to the Myhill-Nerode |
270 tagging-functions. Again to our best knowledge, these tagging-functions have |
333 relation imply that the language is regular is proved by a folklore argument |
271 not been used before to establish the Myhill-Nerode theorem. |
334 of solving equational sytems. For the other part we give two proofs: a |
|
335 direct proof using certain tagging-functions, and an indirect proof using |
|
336 Antimirov's partial derivatives \cite{Antimirov95} (also earlier russion work). |
|
337 Again to our best knowledge, the tagging-functions have not been used before to |
|
338 establish the Myhill-Nerode theorem. |
|
339 |
272 *} |
340 *} |
273 |
341 |
274 section {* Preliminaries *} |
342 section {* Preliminaries *} |
275 |
343 |
276 text {* |
344 text {* |
|
345 \noindent |
277 Strings in Isabelle/HOL are lists of characters with the \emph{empty string} |
346 Strings in Isabelle/HOL are lists of characters with the \emph{empty string} |
278 being represented by the empty list, written @{term "[]"}. \emph{Languages} |
347 being represented by the empty list, written @{term "[]"}. \emph{Languages} |
279 are sets of strings. The language containing all strings is written in |
348 are sets of strings. The language containing all strings is written in |
280 Isabelle/HOL as @{term "UNIV::string set"}. The concatenation of two languages |
349 Isabelle/HOL as @{term "UNIV::string set"}. The concatenation of two languages |
281 is written @{term "A \<cdot> B"} and a language raised to the power @{text n} is written |
350 is written @{term "A \<cdot> B"} and a language raised to the power @{text n} is written |
282 @{term "A \<up> n"}. They are defined as usual |
351 @{term "A \<up> n"}. They are defined as usual |
283 |
352 |
284 \begin{center} |
353 \begin{center} |
285 @{thm Seq_def[THEN eq_reflection, where A1="A" and B1="B"]} |
354 @{thm conc_def'[THEN eq_reflection, where A1="A" and B1="B"]} |
286 \hspace{7mm} |
355 \hspace{7mm} |
287 @{thm pow.simps(1)[THEN eq_reflection, where A1="A"]} |
356 @{thm lang_pow.simps(1)[THEN eq_reflection, where A1="A"]} |
288 \hspace{7mm} |
357 \hspace{7mm} |
289 @{thm pow.simps(2)[THEN eq_reflection, where A1="A" and n1="n"]} |
358 @{thm lang_pow.simps(2)[THEN eq_reflection, where A1="A" and n1="n"]} |
290 \end{center} |
359 \end{center} |
291 |
360 |
292 \noindent |
361 \noindent |
293 where @{text "@"} is the list-append operation. The Kleene-star of a language @{text A} |
362 where @{text "@"} is the list-append operation. The Kleene-star of a language @{text A} |
294 is defined as the union over all powers, namely @{thm Star_def}. In the paper |
363 is defined as the union over all powers, namely @{thm star_def}. In the paper |
295 we will make use of the following properties of these constructions. |
364 we will make use of the following properties of these constructions. |
296 |
365 |
297 \begin{prpstn}\label{langprops}\mbox{}\\ |
366 \begin{prpstn}\label{langprops}\mbox{}\\ |
298 \begin{tabular}{@ {}ll} |
367 \begin{tabular}{@ {}ll} |
299 (i) & @{thm star_cases} \\ |
368 (i) & @{thm star_cases} \\ |
300 (ii) & @{thm[mode=IfThen] pow_length}\\ |
369 (ii) & @{thm[mode=IfThen] pow_length}\\ |
301 (iii) & @{thm seq_Union_left} \\ |
370 (iii) & @{thm conc_Union_left} \\ |
302 \end{tabular} |
371 \end{tabular} |
303 \end{prpstn} |
372 \end{prpstn} |
304 |
373 |
305 \noindent |
374 \noindent |
306 In @{text "(ii)"} we use the notation @{term "length s"} for the length of a |
375 In @{text "(ii)"} we use the notation @{term "length s"} for the length of a |