35 @{text "\<verbclose>"}\isanewline |
35 @{text "\<verbclose>"}\isanewline |
36 @{text "> 7"}\smallskip |
36 @{text "> 7"}\smallskip |
37 \end{graybox} |
37 \end{graybox} |
38 \end{isabelle} |
38 \end{isabelle} |
39 |
39 |
40 Like normal Isabelle proof scripts, |
40 Like normal Isabelle proof scripts, \isacommand{ML}-commands can be |
41 \isacommand{ML}-commands can be evaluated by using the advance and undo buttons of |
41 evaluated by using the advance and undo buttons of your Isabelle |
42 your Isabelle environment. The code inside the \isacommand{ML}-command |
42 environment. The code inside the \isacommand{ML}-command can also contain |
43 can also contain value and function bindings, and even those can be |
43 value and function bindings, and even those can be undone when the proof |
44 undone when the proof script is retracted. As mentioned earlier, we will |
44 script is retracted. As mentioned earlier, we will drop the |
45 drop the \isacommand{ML}~@{text "\<verbopen> \<dots> \<verbclose>"} |
45 \isacommand{ML}~@{text "\<verbopen> \<dots> \<verbclose>"} scaffolding whenever we |
46 scaffolding whenever we show code. |
46 show code. The lines prefixed with @{text ">"} are not part of the |
47 |
47 code, rather they indicate what the response is when the code is evaluated. |
48 Once a portion of code is relatively stable, one usually wants to |
48 |
49 export it to a separate ML-file. Such files can then be included in a |
49 Once a portion of code is relatively stable, you usually want to export it |
50 theory by using the \isacommand{uses}-command in the header of the theory, like: |
50 to a separate ML-file. Such files can then be included in a theory by using |
|
51 the \isacommand{uses}-command in the header of the theory, like: |
51 |
52 |
52 \begin{center} |
53 \begin{center} |
53 \begin{tabular}{@ {}l} |
54 \begin{tabular}{@ {}l} |
54 \isacommand{theory} FirstSteps\\ |
55 \isacommand{theory} FirstSteps\\ |
55 \isacommand{imports} Main\\ |
56 \isacommand{imports} Main\\ |
275 |
278 |
276 section {* Constructing Terms and Types Manually *} |
279 section {* Constructing Terms and Types Manually *} |
277 |
280 |
278 text {* |
281 text {* |
279 While antiquotations are very convenient for constructing terms, they can |
282 While antiquotations are very convenient for constructing terms, they can |
280 only construct fixed terms (remember they are ``linked'' at |
283 only construct fixed terms (remember they are ``linked'' at compile-time). |
281 compile-time). See Recipe~\ref{rec:external} on Page~\pageref{rec:external} |
284 However, you often need to construct terms dynamically. For example, a |
282 for a function that pattern-matches over terms and where the patterns are |
285 function that returns the implication @{text "\<And>(x::\<tau>). P x \<Longrightarrow> Q x"} taking |
283 constructed using antiquotations. However, one often needs to construct |
286 @{term P}, @{term Q} and the type @{term "\<tau>"} as arguments can only be |
284 terms dynamically. For example, a function that returns the implication |
287 written as: |
285 @{text "\<And>(x::\<tau>). P x \<Longrightarrow> Q x"} taking @{term P}, @{term Q} and the type @{term |
288 |
286 "\<tau>"} as arguments can only be written as: |
|
287 *} |
289 *} |
288 |
290 |
289 ML{*fun make_imp P Q tau = |
291 ML{*fun make_imp P Q tau = |
290 let |
292 let |
291 val x = Free ("x",tau) |
293 val x = Free ("x",tau) |
292 in |
294 in |
293 Logic.all x (Logic.mk_implies (P $ x, Q $ x)) |
295 Logic.all x (Logic.mk_implies (P $ x, Q $ x)) |
294 end *} |
296 end *} |
295 |
297 |
296 text {* |
298 text {* |
297 The reason is that one cannot pass the arguments @{term P}, @{term Q} and |
299 The reason is that you cannot pass the arguments @{term P}, @{term Q} and |
298 @{term "tau"} into an antiquotation. For example the following does \emph{not} work: |
300 @{term "tau"} into an antiquotation. For example the following does \emph{not} work: |
299 *} |
301 *} |
300 |
302 |
301 ML{*fun make_wrong_imp P Q tau = @{prop "\<And>x. P x \<Longrightarrow> Q x"} *} |
303 ML{*fun make_wrong_imp P Q tau = @{prop "\<And>x. P x \<Longrightarrow> Q x"} *} |
302 |
304 |
303 text {* |
305 text {* |
304 To see this apply @{text "@{term S}"}, @{text "@{term T}"} and @{text "@{typ nat}"} |
306 To see this apply @{text "@{term S}"}, @{text "@{term T}"} and @{text "@{typ nat}"} |
305 to both functions. With @{ML make_imp} we obtain the intended term involving |
307 to both functions. With @{ML make_imp} we obtain the intended term involving |
306 @{term "S"}, @{text "T"} and @{text "@{typ nat}"} |
308 the given arguments |
307 |
309 |
308 @{ML_response [display,gray] "make_imp @{term S} @{term T} @{typ nat}" |
310 @{ML_response [display,gray] "make_imp @{term S} @{term T} @{typ nat}" |
309 "Const \<dots> $ |
311 "Const \<dots> $ |
310 Abs (\"x\", Type (\"nat\",[]), |
312 Abs (\"x\", Type (\"nat\",[]), |
311 Const \<dots> $ (Free (\"S\",\<dots>) $ \<dots>) $ |
313 Const \<dots> $ (Free (\"S\",\<dots>) $ \<dots>) $ |
340 |
342 |
341 @{ML_response_fake [display,gray] "@{const_name \"Nil\"}" "List.list.Nil"} |
343 @{ML_response_fake [display,gray] "@{const_name \"Nil\"}" "List.list.Nil"} |
342 |
344 |
343 (FIXME: Is it useful to explain @{text "@{const_syntax}"}?) |
345 (FIXME: Is it useful to explain @{text "@{const_syntax}"}?) |
344 |
346 |
345 Similarly, one can construct types manually. For example the function returning |
347 Similarly, you occasionally need to construct types manually. For example |
346 a function type is as follows: |
348 the function returning a function type is as follows: |
347 |
349 |
348 *} |
350 *} |
349 |
351 |
350 ML{*fun make_fun_type tau1 tau2 = Type ("fun",[tau1,tau2]) *} |
352 ML{*fun make_fun_type tau1 tau2 = Type ("fun",[tau1,tau2]) *} |
351 |
353 |
401 |
403 |
402 section {* Type-Checking *} |
404 section {* Type-Checking *} |
403 |
405 |
404 text {* |
406 text {* |
405 |
407 |
406 We can freely construct and manipulate terms, since they are just |
408 You can freely construct and manipulate terms, since they are just |
407 arbitrary unchecked trees. However, we eventually want to see if a |
409 arbitrary unchecked trees. However, you eventually want to see if a |
408 term is well-formed, or type-checks, relative to a theory. |
410 term is well-formed, or type-checks, relative to a theory. |
409 Type-checking is done via the function @{ML cterm_of}, which converts |
411 Type-checking is done via the function @{ML cterm_of}, which converts |
410 a @{ML_type term} into a @{ML_type cterm}, a \emph{certified} term. |
412 a @{ML_type term} into a @{ML_type cterm}, a \emph{certified} term. |
411 Unlike @{ML_type term}s, which are just trees, @{ML_type |
413 Unlike @{ML_type term}s, which are just trees, @{ML_type |
412 "cterm"}s are abstract objects that are guaranteed to be |
414 "cterm"}s are abstract objects that are guaranteed to be |
413 type-correct, and they can only be constructed via ``official |
415 type-correct, and they can only be constructed via ``official |
414 interfaces''. |
416 interfaces''. |
415 |
417 |
416 Type-checking is always relative to a theory context. For now we use |
418 Type-checking is always relative to a theory context. For now we use |
417 the @{ML "@{theory}"} antiquotation to get hold of the current theory. |
419 the @{ML "@{theory}"} antiquotation to get hold of the current theory. |
418 For example we can write |
420 For example you can write: |
419 |
421 |
420 @{ML_response_fake [display,gray] "cterm_of @{theory} @{term \"a + b = c\"}" "a + b = c"} |
422 @{ML_response_fake [display,gray] "cterm_of @{theory} @{term \"a + b = c\"}" "a + b = c"} |
421 |
423 |
422 This can also be wirtten with an antiquotation |
424 This can also be wirtten with an antiquotation: |
423 |
425 |
424 @{ML_response_fake [display,gray] "@{cterm \"(a::nat) + b = c\"}" "a + b = c"} |
426 @{ML_response_fake [display,gray] "@{cterm \"(a::nat) + b = c\"}" "a + b = c"} |
425 |
427 |
426 Attempting to obtain the certified term for |
428 Attempting to obtain the certified term for |
427 |
429 |
428 @{ML_response_fake_both [display,gray] "@{cterm \"1 + True\"}" "Type unification failed \<dots>"} |
430 @{ML_response_fake_both [display,gray] "@{cterm \"1 + True\"}" "Type unification failed \<dots>"} |
429 |
431 |
430 yields an error (since the term is not typable). A slightly more elaborate |
432 yields an error (since the term is not typable). A slightly more elaborate |
431 example that type-checks is |
433 example that type-checks is: |
432 |
|
433 |
434 |
434 @{ML_response_fake [display,gray] |
435 @{ML_response_fake [display,gray] |
435 "let |
436 "let |
436 val natT = @{typ \"nat\"} |
437 val natT = @{typ \"nat\"} |
437 val zero = @{term \"0::nat\"} |
438 val zero = @{term \"0::nat\"} |
517 section {* Theorem Attributes *} |
521 section {* Theorem Attributes *} |
518 |
522 |
519 section {* Printing Terms, CTerms and Theorems\label{sec:printing} *} |
523 section {* Printing Terms, CTerms and Theorems\label{sec:printing} *} |
520 |
524 |
521 text {* |
525 text {* |
522 You will occationally feel the need to inspect terms, cterms or theorems during |
526 During development, you will occationally feel the need to inspect terms, cterms |
523 development. Isabelle contains elaborate pretty-printing functions for that, but |
527 or theorems. Isabelle contains elaborate pretty-printing functions for that, but |
524 for quick-and-dirty solutions they are way too unwieldy. A simple way to transform |
528 for quick-and-dirty solutions they are way too unwieldy. A simple way to transform |
525 a term into a string is to use the function @{ML Syntax.string_of_term}. |
529 a term into a string is to use the function @{ML Syntax.string_of_term}. |
526 |
530 |
527 @{ML_response_fake [display,gray] |
531 @{ML_response_fake [display,gray] |
528 "Syntax.string_of_term @{context} @{term \"1::nat\"}" |
532 "Syntax.string_of_term @{context} @{term \"1::nat\"}" |
540 |
544 |
541 ML{*fun str_of_cterm ctxt t = |
545 ML{*fun str_of_cterm ctxt t = |
542 Syntax.string_of_term ctxt (term_of t)*} |
546 Syntax.string_of_term ctxt (term_of t)*} |
543 |
547 |
544 text {* |
548 text {* |
545 If there are more than one @{ML_type cterm} to be printed, you can use the function |
549 If there are more than one @{ML_type cterm}s to be printed, you can use the |
546 @{ML commas} to conveniently separate them. |
550 function @{ML commas} to separate them. |
547 *} |
551 *} |
548 |
552 |
549 ML{*fun str_of_cterms ctxt ts = |
553 ML{*fun str_of_cterms ctxt ts = |
550 commas (map (str_of_cterm ctxt) ts)*} |
554 commas (map (str_of_cterm ctxt) ts)*} |
551 |
555 |
552 text {* |
556 text {* |
553 The easiest way to get the string of a theorem is to transform it |
557 The easiest way to get the string of a theorem is to transform it |
554 into a @{ML_type cterm} using the function @{ML crep_thm}. |
558 into a @{ML_type cterm} using the function @{ML crep_thm}. |
555 *} |
559 *} |
720 for x}. After that, the function increments the right-hand component of the |
724 for x}. After that, the function increments the right-hand component of the |
721 pair. So finally the result will be @{ML "(x + 1, x + 1)" for x}. |
725 pair. So finally the result will be @{ML "(x + 1, x + 1)" for x}. |
722 |
726 |
723 The combinators @{ML "|>>"} and @{ML "||>"} are defined for |
727 The combinators @{ML "|>>"} and @{ML "||>"} are defined for |
724 functions manipulating pairs. The first applies the function to |
728 functions manipulating pairs. The first applies the function to |
725 the first component of the pair, defined as: |
729 the first component of the pair, defined as |
726 *} |
730 *} |
727 |
731 |
728 ML{*fun (x, y) |>> f = (f x, y)*} |
732 ML{*fun (x, y) |>> f = (f x, y)*} |
729 |
733 |
730 text {* |
734 text {* |