214 txt_raw {*\mbox{}\\[-7mm]*} |
214 txt_raw {*\mbox{}\\[-7mm]*} |
215 ML_prf {* Variable.dest_fixes @{context} *} |
215 ML_prf {* Variable.dest_fixes @{context} *} |
216 txt_raw {*\mbox{}\\[-7mm] \ldots*}(*<*)oops(*>*) |
216 txt_raw {*\mbox{}\\[-7mm] \ldots*}(*<*)oops(*>*) |
217 |
217 |
218 text {* |
218 text {* |
219 The interesting point in this proof is that we injected ML-code before and after |
219 The interesting point is that we injected ML-code before and after |
220 the variables are fixed. For this remember that ML-code inside a proof |
220 the variables are fixed. For this remember that ML-code inside a proof |
221 needs to be enclosed inside \isacommand{ML\_prf}~@{text "\<verbopen> \<dots> \<verbclose>"}, |
221 needs to be enclosed inside \isacommand{ML\_prf}~@{text "\<verbopen> \<dots> \<verbclose>"}, |
222 not \isacommand{ML}~@{text "\<verbopen> \<dots> \<verbclose>"}. The function |
222 not \isacommand{ML}~@{text "\<verbopen> \<dots> \<verbclose>"}. The function |
223 @{ML_ind dest_fixes in Variable} from the structure @{ML_struct Variable} takes |
223 @{ML_ind dest_fixes in Variable} from the structure @{ML_struct Variable} takes |
224 a context and returns all its currently fixed variable (names). That |
224 a context and returns all its currently fixed variable (names). That |
245 text {* |
245 text {* |
246 Here the first time we call @{ML dest_fixes in Variable} we have four fixes variables; |
246 Here the first time we call @{ML dest_fixes in Variable} we have four fixes variables; |
247 the second time we get only the fixes variables @{text x} and @{text y} as answer, since |
247 the second time we get only the fixes variables @{text x} and @{text y} as answer, since |
248 @{text z} and @{text w} are not anymore in the scope of the context. |
248 @{text z} and @{text w} are not anymore in the scope of the context. |
249 This means the curly-braces act on the Isabelle level as opening and closing statements |
249 This means the curly-braces act on the Isabelle level as opening and closing statements |
250 for a context. The above proof fragment corresoponds roughly to the following ML-code |
250 for a context. The above proof fragment corresponds roughly to the following ML-code |
251 *} |
251 *} |
252 |
252 |
253 ML{*val ctxt0 = @{context}; |
253 ML{*val ctxt0 = @{context}; |
254 val ([x, y], ctxt1) = Variable.add_fixes ["x", "y"] ctxt0; |
254 val ([x, y], ctxt1) = Variable.add_fixes ["x", "y"] ctxt0; |
255 val ([z, w], ctxt2) = Variable.add_fixes ["z", "w"] ctxt1*} |
255 val ([z, w], ctxt2) = Variable.add_fixes ["z", "w"] ctxt1*} |
256 |
256 |
257 text {* |
257 text {* |
258 where the function @{ML_ind add_fixes in Variable} fixes a list of variables |
258 where the function @{ML_ind add_fixes in Variable} fixes a list of variables |
259 specified by strings. Let us come back to the point about printing terms. Consider |
259 specified by strings. Let us come back to the point about printing terms. Consider |
260 printing out the term \mbox{@{text "(x, y, z, w)"}} using our function @{ML_ind pretty_term}. |
260 printing out the term \mbox{@{text "(x, y, z, w)"}} using our function @{ML_ind pretty_term}. |
261 This function takes a term and a context as argument. |
261 This function takes a term and a context as argument. Notice how the printing |
|
262 of the term changes with which context is used. |
262 |
263 |
263 \begin{isabelle} |
264 \begin{isabelle} |
264 \begin{graybox} |
265 \begin{graybox} |
265 @{ML "let |
266 @{ML "let |
266 val trm = @{term \"(x, y, z, w)\"} |
267 val trm = @{term \"(x, y, z, w)\"} |
286 \end{graybox} |
287 \end{graybox} |
287 \end{isabelle} |
288 \end{isabelle} |
288 |
289 |
289 |
290 |
290 The term we are printing is in all three cases the same---a tuple containing |
291 The term we are printing is in all three cases the same---a tuple containing |
291 four free variables. As you can see in case of @{ML "ctxt0"}, however, all |
292 four free variables. As you can see, however, in case of @{ML "ctxt0"} all |
292 variables are highlighted indicating a problem, while in case of @{ML |
293 variables are highlighted indicating a problem, while in case of @{ML |
293 "ctxt1"} @{text x} and @{text y} are printed as normal (blue) free |
294 "ctxt1"} @{text x} and @{text y} are printed as normal (blue) free |
294 variables, but not @{text z} and @{text w}. In the last case all variables |
295 variables, but not @{text z} and @{text w}. In the last case all variables |
295 are printed as expected. The point of this example is that the context |
296 are printed as expected. The point of this example is that the context |
296 contains the information which variables are fixed, and designates all other |
297 contains the information which variables are fixed, and designates all other |
302 @{ML_response_fake [gray, display] |
303 @{ML_response_fake [gray, display] |
303 "@{context} |
304 "@{context} |
304 |> Variable.add_fixes [\"x\", \"x\"]" |
305 |> Variable.add_fixes [\"x\", \"x\"]" |
305 "ERROR: Duplicate fixed variable(s): \"x\""} |
306 "ERROR: Duplicate fixed variable(s): \"x\""} |
306 |
307 |
307 But it also allows us to easily create fresh free variables avoiding any |
308 More importantly it also allows us to easily create fresh free variables avoiding any |
308 clashes. In Line~3 below we fix the variable @{text x} in the context |
309 clashes with fixed variables. In Line~3 below we fix the variable @{text x} in the context |
309 @{text ctxt1}. Next we want to create two fresh variables of type @{typ nat} |
310 @{text ctxt1}. Next we want to create two fresh variables of type @{typ nat} |
310 as variants of the string @{text [quotes] "x"}. |
311 as variants of the string @{text [quotes] "x"}. |
311 |
312 |
312 @{ML_response_fake [display, gray, linenos] |
313 @{ML_response_fake [display, gray, linenos] |
313 "let |
314 "let |
319 Variable.variant_frees ctxt1 [] frees) |
320 Variable.variant_frees ctxt1 [] frees) |
320 end" |
321 end" |
321 "([(\"x\", \"nat\"), (\"xa\", \"nat\")], |
322 "([(\"x\", \"nat\"), (\"xa\", \"nat\")], |
322 [(\"xa\", \"nat\"), (\"xb\", \"nat\")])"} |
323 [(\"xa\", \"nat\"), (\"xb\", \"nat\")])"} |
323 |
324 |
324 As can be seen, if we create the fresh variables with the context @{text ctxt0}, |
325 As you can see, if we create the fresh variables with the context @{text ctxt0}, |
325 then we obtain @{text "x"} and @{text "xa"}; but in @{text ctxt1} we obtain @{text "xa"} |
326 then we obtain @{text "x"} and @{text "xa"}; but in @{text ctxt1} we obtain @{text "xa"} |
326 and @{text "xb"} avoiding @{text x}, which was fixed in this context. |
327 and @{text "xb"} avoiding @{text x}, which was fixed in this context. |
327 |
328 |
328 Often one has the situation that given some terms, create fresh variables |
329 Often one has the problem that given some terms, create fresh variables |
329 avoiding any variable occuring in those terms. For this you can use the |
330 avoiding any variable occurring in those terms. For this you can use the |
330 function @{ML_ind declare_term in Variable} from the structure @{ML_struct Variable}. |
331 function @{ML_ind declare_term in Variable} from the structure @{ML_struct Variable}. |
331 |
332 |
332 @{ML_response_fake [gray, display] |
333 @{ML_response_fake [gray, display] |
333 "let |
334 "let |
334 val ctxt1 = Variable.declare_term @{term \"(x, xa)\"} @{context} |
335 val ctxt1 = Variable.declare_term @{term \"(x, xa)\"} @{context} |
336 in |
337 in |
337 Variable.variant_frees ctxt1 [] frees |
338 Variable.variant_frees ctxt1 [] frees |
338 end" |
339 end" |
339 "[(\"xb\", \"nat\"), (\"xc\", \"nat\")]"} |
340 "[(\"xb\", \"nat\"), (\"xc\", \"nat\")]"} |
340 |
341 |
341 The result is @{text xb} and @{text xc} for the names of the freshh variables. This |
342 The result is @{text xb} and @{text xc} for the names of the fresh |
342 is also important when parsing terms, for example with the function |
343 variables. Note that @{ML_ind declare_term in Variable} does not fix the |
343 @{ML_ind read_term in Syntax} from the structure @{ML_struct Syntax}. Consider |
344 variables; it just makes them ``known'' to the context. This is helpful when |
344 the following code: |
345 parsing terms using the function @{ML_ind read_term in Syntax} from the |
|
346 structure @{ML_struct Syntax}. Consider the following code: |
345 |
347 |
346 @{ML_response_fake [gray, display] |
348 @{ML_response_fake [gray, display] |
347 "let |
349 "let |
348 val ctxt0 = @{context} |
350 val ctxt0 = @{context} |
349 val ctxt1 = Variable.declare_term @{term \"x::nat\"} ctxt0 |
351 val ctxt1 = Variable.declare_term @{term \"x::nat\"} ctxt0 |
351 (Syntax.read_term ctxt0 \"x\", |
353 (Syntax.read_term ctxt0 \"x\", |
352 Syntax.read_term ctxt1 \"x\") |
354 Syntax.read_term ctxt1 \"x\") |
353 end" |
355 end" |
354 "(Free (\"x\", \"'a\"), Free (\"x\", \"nat\"))"} |
356 "(Free (\"x\", \"'a\"), Free (\"x\", \"nat\"))"} |
355 |
357 |
356 Parsing the string in the first context results in a free variable |
358 Parsing the string in the context @{text "ctxt0"} results in a free variable |
357 with a default polymorphic type, but in the second case we obtain a |
359 with a default polymorphic type, but in case of @{text "ctxt1"} we obtain a |
358 free variable of type @{typ nat} as previously declared. Which |
360 free variable of type @{typ nat} as previously declared. Which |
359 type the parsed term receives depends on the last declaration that |
361 type the parsed term receives depends upon the last declaration that |
360 is made as the next example illustrates. |
362 is made, as the next example illustrates. |
361 |
363 |
362 @{ML_response_fake [gray, display] |
364 @{ML_response_fake [gray, display] |
363 "let |
365 "let |
364 val ctxt1 = Variable.declare_term @{term \"x::nat\"} @{context} |
366 val ctxt1 = Variable.declare_term @{term \"x::nat\"} @{context} |
365 val ctxt2 = Variable.declare_term @{term \"x::int\"} ctxt1 |
367 val ctxt2 = Variable.declare_term @{term \"x::int\"} ctxt1 |
367 (Syntax.read_term ctxt1 \"x\", |
369 (Syntax.read_term ctxt1 \"x\", |
368 Syntax.read_term ctxt2 \"x\") |
370 Syntax.read_term ctxt2 \"x\") |
369 end" |
371 end" |
370 "(Free (\"x\", \"nat\"), Free (\"x\", \"int\"))"} |
372 "(Free (\"x\", \"nat\"), Free (\"x\", \"int\"))"} |
371 |
373 |
|
374 The most useful feature of contexts is that one can export, for example, |
|
375 terms between contexts. |
372 *} |
376 *} |
373 |
377 |
374 ML {* |
378 ML {* |
375 let |
379 let |
376 val ctxt0 = @{context} |
380 val ctxt0 = @{context} |
377 val trm = @{prop "P x y z"} |
|
378 val foo_thm = Skip_Proof.make_thm (Proof_Context.theory_of ctxt0) trm |
|
379 val (_, ctxt1) = Variable.add_fixes ["x", "y", "z"] ctxt0 |
381 val (_, ctxt1) = Variable.add_fixes ["x", "y", "z"] ctxt0 |
|
382 val foo_trm = @{term "P x y z"} |
|
383 in |
|
384 singleton (Variable.export_terms ctxt1 ctxt0) foo_trm |
|
385 |> pretty_term ctxt1 |
|
386 |> pwriteln |
|
387 end |
|
388 *} |
|
389 |
|
390 ML {* |
|
391 let |
|
392 val thy = @{theory} |
|
393 val ctxt0 = @{context} |
|
394 val (_, ctxt1) = Variable.add_fixes ["x", "y", "z"] ctxt0 |
|
395 val foo_thm = Skip_Proof.make_thm thy @{prop "P x y z"} |
|
396 in |
|
397 singleton (Proof_Context.export ctxt1 ctxt0) foo_thm |
|
398 end |
|
399 *} |
|
400 |
|
401 ML {* |
|
402 let |
|
403 val thy = @{theory} |
|
404 val ctxt0 = @{context} |
|
405 val (_, ctxt1) = Variable.add_fixes ["x", "y", "z"] ctxt0 |
|
406 val foo_thm = Skip_Proof.make_thm thy @{prop "P x y z"} |
380 in |
407 in |
381 singleton (Proof_Context.export ctxt1 ctxt0) foo_thm |
408 singleton (Proof_Context.export ctxt1 ctxt0) foo_thm |
382 end |
409 end |
383 *} |
410 *} |
384 |
411 |