213 This function takes a term and a context as argument. Notice how the printing |
212 This function takes a term and a context as argument. Notice how the printing |
214 of the term changes according to which context is used. |
213 of the term changes according to which context is used. |
215 |
214 |
216 \begin{isabelle} |
215 \begin{isabelle} |
217 \begin{graybox} |
216 \begin{graybox} |
218 @{ML "let |
217 @{ML \<open>let |
219 val trm = @{term \"(x, y, z, w)\"} |
218 val trm = @{term "(x, y, z, w)"} |
220 in |
219 in |
221 pwriteln (Pretty.chunks |
220 pwriteln (Pretty.chunks |
222 [ pretty_term ctxt0 trm, |
221 [ pretty_term ctxt0 trm, |
223 pretty_term ctxt1 trm, |
222 pretty_term ctxt1 trm, |
224 pretty_term ctxt2 trm ]) |
223 pretty_term ctxt2 trm ]) |
225 end"}\\ |
224 end\<close>}\\ |
226 \setlength{\fboxsep}{0mm} |
225 \setlength{\fboxsep}{0mm} |
227 \<open>>\<close>~\<open>(\<close>\colorbox{gray!5}{\raisebox{0mm}[3mm][1mm]{\<open>x\<close>}}\<open>,\<close>~% |
226 \<open>>\<close>~\<open>(\<close>\colorbox{gray!5}{\raisebox{0mm}[3mm][1mm]{\<open>x\<close>}}\<open>,\<close>~% |
228 \colorbox{gray!5}{\raisebox{0mm}[3mm][1mm]{\<open>y\<close>}}\<open>,\<close>~% |
227 \colorbox{gray!5}{\raisebox{0mm}[3mm][1mm]{\<open>y\<close>}}\<open>,\<close>~% |
229 \colorbox{gray!5}{\raisebox{0mm}[3mm][1mm]{\<open>z\<close>}}\<open>,\<close>~% |
228 \colorbox{gray!5}{\raisebox{0mm}[3mm][1mm]{\<open>z\<close>}}\<open>,\<close>~% |
230 \colorbox{gray!5}{\raisebox{0mm}[3mm][1mm]{\<open>w\<close>}}\<open>)\<close>\\ |
229 \colorbox{gray!5}{\raisebox{0mm}[3mm][1mm]{\<open>w\<close>}}\<open>)\<close>\\ |
239 \end{graybox} |
238 \end{graybox} |
240 \end{isabelle} |
239 \end{isabelle} |
241 |
240 |
242 |
241 |
243 The term we are printing is in all three cases the same---a tuple containing |
242 The term we are printing is in all three cases the same---a tuple containing |
244 four free variables. As you can see, however, in case of @{ML "ctxt0"} all |
243 four free variables. As you can see, however, in case of @{ML \<open>ctxt0\<close>} all |
245 variables are highlighted indicating a problem, while in case of @{ML |
244 variables are highlighted indicating a problem, while in case of @{ML \<open>ctxt1\<close>} \<open>x\<close> and \<open>y\<close> are printed as normal (blue) free |
246 "ctxt1"} \<open>x\<close> and \<open>y\<close> are printed as normal (blue) free |
|
247 variables, but not \<open>z\<close> and \<open>w\<close>. In the last case all variables |
245 variables, but not \<open>z\<close> and \<open>w\<close>. In the last case all variables |
248 are printed as expected. The point of this example is that the context |
246 are printed as expected. The point of this example is that the context |
249 contains the information which variables are fixed, and designates all other |
247 contains the information which variables are fixed, and designates all other |
250 free variables as being alien or faulty. Therefore the highlighting. |
248 free variables as being alien or faulty. Therefore the highlighting. |
251 While this seems like a minor detail, the concept of making the context aware |
249 While this seems like a minor detail, the concept of making the context aware |
252 of fixed variables is actually quite useful. For example it prevents us from |
250 of fixed variables is actually quite useful. For example it prevents us from |
253 fixing a variable twice |
251 fixing a variable twice |
254 |
252 |
255 @{ML_matchresult_fake [gray, display] |
253 @{ML_matchresult_fake [gray, display] |
256 "@{context} |
254 \<open>@{context} |
257 |> Variable.add_fixes [\"x\", \"x\"]" |
255 |> Variable.add_fixes ["x", "x"]\<close> |
258 "ERROR: Duplicate fixed variable(s): \"x\""} |
256 \<open>ERROR: Duplicate fixed variable(s): "x"\<close>} |
259 |
257 |
260 More importantly it also allows us to easily create fresh names for |
258 More importantly it also allows us to easily create fresh names for |
261 fixed variables. For this you have to use the function @{ML_ind |
259 fixed variables. For this you have to use the function @{ML_ind |
262 variant_fixes in Variable} from the structure @{ML_structure Variable}. |
260 variant_fixes in Variable} from the structure @{ML_structure Variable}. |
263 |
261 |
264 @{ML_matchresult_fake [gray, display] |
262 @{ML_matchresult_fake [gray, display] |
265 "@{context} |
263 \<open>@{context} |
266 |> Variable.variant_fixes [\"y\", \"y\", \"z\"]" |
264 |> Variable.variant_fixes ["y", "y", "z"]\<close> |
267 "([\"y\", \"ya\", \"z\"], ...)"} |
265 \<open>(["y", "ya", "z"], ...)\<close>} |
268 |
266 |
269 Now a fresh variant for the second occurence of \<open>y\<close> is created |
267 Now a fresh variant for the second occurence of \<open>y\<close> is created |
270 avoiding any clash. In this way we can also create fresh free variables |
268 avoiding any clash. In this way we can also create fresh free variables |
271 that avoid any clashes with fixed variables. In Line~3 below we fix |
269 that avoid any clashes with fixed variables. In Line~3 below we fix |
272 the variable \<open>x\<close> in the context \<open>ctxt1\<close>. Next we want to |
270 the variable \<open>x\<close> in the context \<open>ctxt1\<close>. Next we want to |
273 create two fresh variables of type @{typ nat} as variants of the |
271 create two fresh variables of type @{typ nat} as variants of the |
274 string @{text [quotes] "x"} (Lines 6 and 7). |
272 string @{text [quotes] "x"} (Lines 6 and 7). |
275 |
273 |
276 @{ML_matchresult_fake [display, gray, linenos] |
274 @{ML_matchresult_fake [display, gray, linenos] |
277 "let |
275 \<open>let |
278 val ctxt0 = @{context} |
276 val ctxt0 = @{context} |
279 val (_, ctxt1) = Variable.add_fixes [\"x\"] ctxt0 |
277 val (_, ctxt1) = Variable.add_fixes ["x"] ctxt0 |
280 val frees = replicate 2 (\"x\", @{typ nat}) |
278 val frees = replicate 2 ("x", @{typ nat}) |
281 in |
279 in |
282 (Variable.variant_frees ctxt0 [] frees, |
280 (Variable.variant_frees ctxt0 [] frees, |
283 Variable.variant_frees ctxt1 [] frees) |
281 Variable.variant_frees ctxt1 [] frees) |
284 end" |
282 end\<close> |
285 "([(\"x\", \"nat\"), (\"xa\", \"nat\")], |
283 \<open>([("x", "nat"), ("xa", "nat")], |
286 [(\"xa\", \"nat\"), (\"xb\", \"nat\")])"} |
284 [("xa", "nat"), ("xb", "nat")])\<close>} |
287 |
285 |
288 As you can see, if we create the fresh variables with the context \<open>ctxt0\<close>, |
286 As you can see, if we create the fresh variables with the context \<open>ctxt0\<close>, |
289 then we obtain \<open>x\<close> and \<open>xa\<close>; but in \<open>ctxt1\<close> we obtain \<open>xa\<close> |
287 then we obtain \<open>x\<close> and \<open>xa\<close>; but in \<open>ctxt1\<close> we obtain \<open>xa\<close> |
290 and \<open>xb\<close> avoiding \<open>x\<close>, which was fixed in this context. |
288 and \<open>xb\<close> avoiding \<open>x\<close>, which was fixed in this context. |
291 |
289 |
292 Often one has the problem that given some terms, create fresh variables |
290 Often one has the problem that given some terms, create fresh variables |
293 avoiding any variable occurring in those terms. For this you can use the |
291 avoiding any variable occurring in those terms. For this you can use the |
294 function @{ML_ind declare_term in Variable} from the structure @{ML_structure Variable}. |
292 function @{ML_ind declare_term in Variable} from the structure @{ML_structure Variable}. |
295 |
293 |
296 @{ML_matchresult_fake [gray, display] |
294 @{ML_matchresult_fake [gray, display] |
297 "let |
295 \<open>let |
298 val ctxt1 = Variable.declare_term @{term \"(x, xa)\"} @{context} |
296 val ctxt1 = Variable.declare_term @{term "(x, xa)"} @{context} |
299 val frees = replicate 2 (\"x\", @{typ nat}) |
297 val frees = replicate 2 ("x", @{typ nat}) |
300 in |
298 in |
301 Variable.variant_frees ctxt1 [] frees |
299 Variable.variant_frees ctxt1 [] frees |
302 end" |
300 end\<close> |
303 "[(\"xb\", \"nat\"), (\"xc\", \"nat\")]"} |
301 \<open>[("xb", "nat"), ("xc", "nat")]\<close>} |
304 |
302 |
305 The result is \<open>xb\<close> and \<open>xc\<close> for the names of the fresh |
303 The result is \<open>xb\<close> and \<open>xc\<close> for the names of the fresh |
306 variables, since \<open>x\<close> and \<open>xa\<close> occur in the term we declared. |
304 variables, since \<open>x\<close> and \<open>xa\<close> occur in the term we declared. |
307 Note that @{ML_ind declare_term in Variable} does not fix the |
305 Note that @{ML_ind declare_term in Variable} does not fix the |
308 variables; it just makes them ``known'' to the context. You can see |
306 variables; it just makes them ``known'' to the context. You can see |
309 that if you print out a declared term. |
307 that if you print out a declared term. |
310 |
308 |
311 \begin{isabelle} |
309 \begin{isabelle} |
312 \begin{graybox} |
310 \begin{graybox} |
313 @{ML "let |
311 @{ML \<open>let |
314 val trm = @{term \"P x y z\"} |
312 val trm = @{term "P x y z"} |
315 val ctxt1 = Variable.declare_term trm @{context} |
313 val ctxt1 = Variable.declare_term trm @{context} |
316 in |
314 in |
317 pwriteln (pretty_term ctxt1 trm) |
315 pwriteln (pretty_term ctxt1 trm) |
318 end"}\\ |
316 end\<close>}\\ |
319 \setlength{\fboxsep}{0mm} |
317 \setlength{\fboxsep}{0mm} |
320 \<open>>\<close>~\colorbox{gray!5}{\raisebox{0mm}[3mm][1mm]{\<open>P\<close>}}~% |
318 \<open>>\<close>~\colorbox{gray!5}{\raisebox{0mm}[3mm][1mm]{\<open>P\<close>}}~% |
321 \colorbox{gray!5}{\raisebox{0mm}[3mm][1mm]{\<open>x\<close>}}~% |
319 \colorbox{gray!5}{\raisebox{0mm}[3mm][1mm]{\<open>x\<close>}}~% |
322 \colorbox{gray!5}{\raisebox{0mm}[3mm][1mm]{\<open>y\<close>}}~% |
320 \colorbox{gray!5}{\raisebox{0mm}[3mm][1mm]{\<open>y\<close>}}~% |
323 \colorbox{gray!5}{\raisebox{0mm}[3mm][1mm]{\<open>z\<close>}} |
321 \colorbox{gray!5}{\raisebox{0mm}[3mm][1mm]{\<open>z\<close>}} |
328 fixed. However, declaring a term is helpful when parsing terms using |
326 fixed. However, declaring a term is helpful when parsing terms using |
329 the function @{ML_ind read_term in Syntax} from the structure |
327 the function @{ML_ind read_term in Syntax} from the structure |
330 @{ML_structure Syntax}. Consider the following code: |
328 @{ML_structure Syntax}. Consider the following code: |
331 |
329 |
332 @{ML_matchresult_fake [gray, display] |
330 @{ML_matchresult_fake [gray, display] |
333 "let |
331 \<open>let |
334 val ctxt0 = @{context} |
332 val ctxt0 = @{context} |
335 val ctxt1 = Variable.declare_term @{term \"x::nat\"} ctxt0 |
333 val ctxt1 = Variable.declare_term @{term "x::nat"} ctxt0 |
336 in |
334 in |
337 (Syntax.read_term ctxt0 \"x\", |
335 (Syntax.read_term ctxt0 "x", |
338 Syntax.read_term ctxt1 \"x\") |
336 Syntax.read_term ctxt1 "x") |
339 end" |
337 end\<close> |
340 "(Free (\"x\", \"'a\"), Free (\"x\", \"nat\"))"} |
338 \<open>(Free ("x", "'a"), Free ("x", "nat"))\<close>} |
341 |
339 |
342 Parsing the string in the context \<open>ctxt0\<close> results in a free variable |
340 Parsing the string in the context \<open>ctxt0\<close> results in a free variable |
343 with a default polymorphic type, but in case of \<open>ctxt1\<close> we obtain a |
341 with a default polymorphic type, but in case of \<open>ctxt1\<close> we obtain a |
344 free variable of type @{typ nat} as previously declared. Which |
342 free variable of type @{typ nat} as previously declared. Which |
345 type the parsed term receives depends upon the last declaration that |
343 type the parsed term receives depends upon the last declaration that |
346 is made, as the next example illustrates. |
344 is made, as the next example illustrates. |
347 |
345 |
348 @{ML_matchresult_fake [gray, display] |
346 @{ML_matchresult_fake [gray, display] |
349 "let |
347 \<open>let |
350 val ctxt1 = Variable.declare_term @{term \"x::nat\"} @{context} |
348 val ctxt1 = Variable.declare_term @{term "x::nat"} @{context} |
351 val ctxt2 = Variable.declare_term @{term \"x::int\"} ctxt1 |
349 val ctxt2 = Variable.declare_term @{term "x::int"} ctxt1 |
352 in |
350 in |
353 (Syntax.read_term ctxt1 \"x\", |
351 (Syntax.read_term ctxt1 "x", |
354 Syntax.read_term ctxt2 \"x\") |
352 Syntax.read_term ctxt2 "x") |
355 end" |
353 end\<close> |
356 "(Free (\"x\", \"nat\"), Free (\"x\", \"int\"))"} |
354 \<open>(Free ("x", "nat"), Free ("x", "int"))\<close>} |
357 |
355 |
358 The most useful feature of contexts is that one can export, or transfer, |
356 The most useful feature of contexts is that one can export, or transfer, |
359 terms and theorems between them. We show this first for terms. |
357 terms and theorems between them. We show this first for terms. |
360 |
358 |
361 \begin{isabelle} |
359 \begin{isabelle} |
362 \begin{graybox} |
360 \begin{graybox} |
363 \begin{linenos} |
361 \begin{linenos} |
364 @{ML "let |
362 @{ML \<open>let |
365 val ctxt0 = @{context} |
363 val ctxt0 = @{context} |
366 val (_, ctxt1) = Variable.add_fixes [\"x\", \"y\", \"z\"] ctxt0 |
364 val (_, ctxt1) = Variable.add_fixes ["x", "y", "z"] ctxt0 |
367 val foo_trm = @{term \"P x y z\"} |
365 val foo_trm = @{term "P x y z"} |
368 in |
366 in |
369 singleton (Variable.export_terms ctxt1 ctxt0) foo_trm |
367 singleton (Variable.export_terms ctxt1 ctxt0) foo_trm |
370 |> pretty_term ctxt0 |
368 |> pretty_term ctxt0 |
371 |> pwriteln |
369 |> pwriteln |
372 end"} |
370 end\<close>} |
373 \end{linenos} |
371 \end{linenos} |
374 \setlength{\fboxsep}{0mm} |
372 \setlength{\fboxsep}{0mm} |
375 \<open>>\<close>~\colorbox{gray!5}{\raisebox{0mm}[3mm][1mm]{\<open>P\<close>}}~% |
373 \<open>>\<close>~\colorbox{gray!5}{\raisebox{0mm}[3mm][1mm]{\<open>P\<close>}}~% |
376 \<open>?x ?y ?z\<close> |
374 \<open>?x ?y ?z\<close> |
377 \end{graybox} |
375 \end{graybox} |
399 structure @{ML_structure Skip_Proof}. This function will turn an arbitray |
397 structure @{ML_structure Skip_Proof}. This function will turn an arbitray |
400 term, in our case @{term "P x y z x y z"}, into a theorem (disregarding |
398 term, in our case @{term "P x y z x y z"}, into a theorem (disregarding |
401 whether it is actually provable). |
399 whether it is actually provable). |
402 |
400 |
403 @{ML_matchresult_fake [display, gray] |
401 @{ML_matchresult_fake [display, gray] |
404 "let |
402 \<open>let |
405 val thy = @{theory} |
403 val thy = @{theory} |
406 val ctxt0 = @{context} |
404 val ctxt0 = @{context} |
407 val (_, ctxt1) = Variable.add_fixes [\"P\", \"x\", \"y\", \"z\"] ctxt0 |
405 val (_, ctxt1) = Variable.add_fixes ["P", "x", "y", "z"] ctxt0 |
408 val foo_thm = Skip_Proof.make_thm thy @{prop \"P x y z x y z\"} |
406 val foo_thm = Skip_Proof.make_thm thy @{prop "P x y z x y z"} |
409 in |
407 in |
410 singleton (Proof_Context.export ctxt1 ctxt0) foo_thm |
408 singleton (Proof_Context.export ctxt1 ctxt0) foo_thm |
411 end" |
409 end\<close> |
412 "?P ?x ?y ?z ?x ?y ?z"} |
410 \<open>?P ?x ?y ?z ?x ?y ?z\<close>} |
413 |
411 |
414 Since we fixed all variables in \<open>ctxt1\<close>, in the exported |
412 Since we fixed all variables in \<open>ctxt1\<close>, in the exported |
415 result all of them are schematic. The great point of contexts is |
413 result all of them are schematic. The great point of contexts is |
416 that exporting from one to another is not just restricted to |
414 that exporting from one to another is not just restricted to |
417 variables, but also works with assumptions. For this we can use the |
415 variables, but also works with assumptions. For this we can use the |
418 function @{ML_ind export in Assumption} from the structure |
416 function @{ML_ind export in Assumption} from the structure |
419 @{ML_structure Assumption}. Consider the following code. |
417 @{ML_structure Assumption}. Consider the following code. |
420 |
418 |
421 @{ML_matchresult_fake [display, gray, linenos] |
419 @{ML_matchresult_fake [display, gray, linenos] |
422 "let |
420 \<open>let |
423 val ctxt0 = @{context} |
421 val ctxt0 = @{context} |
424 val ([eq], ctxt1) = Assumption.add_assumes [@{cprop \"x \<equiv> y\"}] ctxt0 |
422 val ([eq], ctxt1) = Assumption.add_assumes [@{cprop "x \<equiv> y"}] ctxt0 |
425 val eq' = Thm.symmetric eq |
423 val eq' = Thm.symmetric eq |
426 in |
424 in |
427 Assumption.export false ctxt1 ctxt0 eq' |
425 Assumption.export false ctxt1 ctxt0 eq' |
428 end" |
426 end\<close> |
429 "x \<equiv> y \<Longrightarrow> y \<equiv> x"} |
427 \<open>x \<equiv> y \<Longrightarrow> y \<equiv> x\<close>} |
430 |
428 |
431 The function @{ML_ind add_assumes in Assumption} from the structure |
429 The function @{ML_ind add_assumes in Assumption} from the structure |
432 @{ML_structure Assumption} adds the assumption \mbox{\<open>x \<equiv> y\<close>} |
430 @{ML_structure Assumption} adds the assumption \mbox{\<open>x \<equiv> y\<close>} |
433 to the context \<open>ctxt1\<close> (Line 3). This function expects a list |
431 to the context \<open>ctxt1\<close> (Line 3). This function expects a list |
434 of @{ML_type cterm}s and returns them as theorems, together with the |
432 of @{ML_type cterm}s and returns them as theorems, together with the |