42 \isacommand{ML}-commands can be evaluated by using the advance and undo buttons of |
42 \isacommand{ML}-commands can be evaluated by using the advance and undo buttons of |
43 your Isabelle environment. The code inside the \isacommand{ML}-command |
43 your Isabelle environment. The code inside the \isacommand{ML}-command |
44 can also contain value and function bindings, and even those can be |
44 can also contain value and function bindings, and even those can be |
45 undone when the proof script is retracted. As mentioned earlier, we will |
45 undone when the proof script is retracted. As mentioned earlier, we will |
46 drop the \isacommand{ML} \isa{\isacharverbatimopen \ldots \isacharverbatimclose} |
46 drop the \isacommand{ML} \isa{\isacharverbatimopen \ldots \isacharverbatimclose} |
47 whenever we show code and its response. |
47 whenever we show code. |
48 |
48 |
49 Once a portion of code is relatively stable, one usually wants to |
49 Once a portion of code is relatively stable, one usually wants to |
50 export it to a separate ML-file. Such files can then be included in a |
50 export it to a separate ML-file. Such files can then be included in a |
51 theory by using \isacommand{uses} in the header of the theory, like |
51 theory by using \isacommand{uses} in the header of the theory, like |
52 |
52 |
78 converting values into strings, namely using the function @{ML makestring}: |
78 converting values into strings, namely using the function @{ML makestring}: |
79 |
79 |
80 @{ML_response_fake [display,gray] "warning (makestring 1)" "\"1\""} |
80 @{ML_response_fake [display,gray] "warning (makestring 1)" "\"1\""} |
81 |
81 |
82 However @{ML makestring} only works if the type of what is converted is monomorphic |
82 However @{ML makestring} only works if the type of what is converted is monomorphic |
83 and is not a function. |
83 and not a function. |
84 |
84 |
85 The function @{ML "warning"} should only be used for testing purposes, because any |
85 The function @{ML "warning"} should only be used for testing purposes, because any |
86 output this function generates will be overwritten as soon as an error is |
86 output this function generates will be overwritten as soon as an error is |
87 raised. For printing anything more serious and elaborate, the |
87 raised. For printing anything more serious and elaborate, the |
88 function @{ML tracing} is more appropriate. This function writes all output into |
88 function @{ML tracing} is more appropriate. This function writes all output into |
89 a separate tracing buffer. For example |
89 a separate tracing buffer. For example |
90 |
90 |
91 @{ML_response_fake [display,gray] "tracing \"foo\"" "\"foo\""} |
91 @{ML_response_fake [display,gray] "tracing \"foo\"" "\"foo\""} |
92 |
92 |
93 It is also possible to redirect the ``channel'' where the string @{text "foo"} is |
93 It is also possible to redirect the ``channel'' where the string @{text "foo"} is |
94 printed to a separate file, e.g. to prevent ProofGeneral from choking on massive |
94 printed to a separate file, e.g.~to prevent ProofGeneral from choking on massive |
95 amounts of trace output. This redirection can be achieved using the code |
95 amounts of trace output. This redirection can be achieved using the code |
96 *} |
96 *} |
97 |
97 |
98 ML{*val strip_specials = |
98 ML{*val strip_specials = |
99 let |
99 let |
165 val ({rules,...},_) = MetaSimplifier.rep_ss @{simpset} |
165 val ({rules,...},_) = MetaSimplifier.rep_ss @{simpset} |
166 in |
166 in |
167 map #name (Net.entries rules) |
167 map #name (Net.entries rules) |
168 end" "[\"Nat.of_nat_eq_id\", \"Int.of_int_eq_id\", \"Nat.One_nat_def\", \<dots>]"} |
168 end" "[\"Nat.of_nat_eq_id\", \"Int.of_int_eq_id\", \"Nat.One_nat_def\", \<dots>]"} |
169 |
169 |
170 The code above extracts the theorem names that are stored in a simpset. |
170 The code above extracts the theorem names that are stored in the current simpset. |
171 We refer to the current simpset with the antiquotation @{text "@{simpset}"}. |
171 We refer to the simpset with the antiquotation @{text "@{simpset}"}. |
172 The function @{ML rep_ss in MetaSimplifier} returns a record |
172 The function @{ML rep_ss in MetaSimplifier} returns a record |
173 containing all information about the simpset. The rules of a simpset are stored |
173 containing all information about the simpset. The rules of a simpset are stored |
174 in a discrimination net (a datastructure for fast indexing). From this net |
174 in a \emph{discrimination net} (a datastructure for fast indexing). From this net |
175 we can extract the entries using the function @{ML Net.entries}. |
175 we can extract the entries using the function @{ML Net.entries}. |
176 |
176 |
177 \begin{readmore} |
177 \begin{readmore} |
178 The infrastructure for simpsets is implemented in @{ML_file "Pure/meta_simplifier.ML"} |
178 The infrastructure for simpsets is contained in @{ML_file "Pure/meta_simplifier.ML"} |
179 and @{ML_file "Pure/simplifier.ML"}. |
179 and @{ML_file "Pure/simplifier.ML"}. Discrimination nets are implemented |
|
180 in @{ML_file "Pure/net.ML"}. |
180 \end{readmore} |
181 \end{readmore} |
181 |
182 |
182 While antiquotations have many applications, they were originally introduced in order |
183 While antiquotations have many applications, they were originally introduced in order |
183 to avoid explicit bindings for theorems such as |
184 to avoid explicit bindings for theorems such as |
184 *} |
185 *} |
185 |
186 |
186 ML{*val allI = thm "allI" *} |
187 ML{*val allI = thm "allI" *} |
187 |
188 |
188 text {* |
189 text {* |
189 These bindings were difficult to maintain and also could be accidentally |
190 These bindings are difficult to maintain and also can be accidentally |
190 overwritten by the user. This usually broke definitional |
191 overwritten by the user. This often breakes definitional |
191 packages. Antiquotations solve this problem, since they are ``linked'' |
192 packages. Antiquotations solve this problem, since they are ``linked'' |
192 statically at compile-time. However, this static linkage also limits their |
193 statically at compile-time. However, this static linkage also limits their |
193 usefulness in cases where data needs to be build up dynamically. In the course of |
194 usefulness in cases where data needs to be build up dynamically. In the course of |
194 this introduction, we will learn more about |
195 this introduction, we will learn more about |
195 these antiquotations: they greatly simplify Isabelle programming since one |
196 these antiquotations: they greatly simplify Isabelle programming since one |
218 binds the corresponding variable. However, in Isabelle the names of bound variables are |
219 binds the corresponding variable. However, in Isabelle the names of bound variables are |
219 kept at abstractions for printing purposes, and so should be treated only as comments. |
220 kept at abstractions for printing purposes, and so should be treated only as comments. |
220 |
221 |
221 \begin{readmore} |
222 \begin{readmore} |
222 Terms are described in detail in \isccite{sec:terms}. Their |
223 Terms are described in detail in \isccite{sec:terms}. Their |
223 definition and many useful operations can be found in @{ML_file "Pure/term.ML"}. |
224 definition and many useful operations are implemented in @{ML_file "Pure/term.ML"}. |
224 \end{readmore} |
225 \end{readmore} |
225 |
226 |
226 Sometimes the internal representation of terms can be surprisingly different |
227 Sometimes the internal representation of terms can be surprisingly different |
227 from what you see at the user level, because the layers of |
228 from what you see at the user level, because the layers of |
228 parsing/type-checking/pretty printing can be quite elaborate. |
229 parsing/type-checking/pretty printing can be quite elaborate. |
263 |
264 |
264 @{ML_response_fake [display,gray] "@{typ \"bool \<Rightarrow> nat\"}" "bool \<Rightarrow> nat"} |
265 @{ML_response_fake [display,gray] "@{typ \"bool \<Rightarrow> nat\"}" "bool \<Rightarrow> nat"} |
265 |
266 |
266 \begin{readmore} |
267 \begin{readmore} |
267 Types are described in detail in \isccite{sec:types}. Their |
268 Types are described in detail in \isccite{sec:types}. Their |
268 definition and many useful operations can also be found in @{ML_file "Pure/type.ML"}. |
269 definition and many useful operations are implemented |
|
270 in @{ML_file "Pure/type.ML"}. |
269 \end{readmore} |
271 \end{readmore} |
270 *} |
272 *} |
271 |
273 |
272 |
274 |
273 section {* Constructing Terms and Types Manually *} |
275 section {* Constructing Terms and Types Manually *} |
274 |
276 |
275 text {* |
277 text {* |
276 |
278 |
277 While antiquotations are very convenient for constructing terms and types, |
279 While antiquotations are very convenient for constructing terms, |
278 they can only construct fixed terms (remember they are ``linked'' at compile-time). |
280 they can only construct fixed terms (remember they are ``linked'' at compile-time). |
279 However, one often needs to construct terms |
281 However, one often needs to construct terms |
280 dynamically. For example, a function that returns the implication |
282 dynamically. For example, a function that returns the implication |
281 @{text "\<And>(x::\<tau>). P x \<Longrightarrow> Q x"} taking @{term P}, @{term Q} and the type @{term "\<tau>"} |
283 @{text "\<And>(x::\<tau>). P x \<Longrightarrow> Q x"} taking @{term P}, @{term Q} and the type @{term "\<tau>"} |
282 as arguments can only be written as |
284 as arguments can only be written as |
306 "Const \<dots> $ |
308 "Const \<dots> $ |
307 Abs (\"x\", Type (\"nat\",[]), |
309 Abs (\"x\", Type (\"nat\",[]), |
308 Const \<dots> $ (Free (\"S\",\<dots>) $ \<dots>) $ |
310 Const \<dots> $ (Free (\"S\",\<dots>) $ \<dots>) $ |
309 (Free (\"T\",\<dots>) $ \<dots>))"} |
311 (Free (\"T\",\<dots>) $ \<dots>))"} |
310 |
312 |
311 With @{ML make_wrong_imp} we obtain a term involving the @{term "P"} |
313 Whereas with @{ML make_wrong_imp} we obtain a term involving the @{term "P"} |
312 and @{text "Q"} from the antiquotation. |
314 and @{text "Q"} from the antiquotation. |
313 |
315 |
314 @{ML_response [display,gray] "make_wrong_imp @{term S} @{term T} @{typ nat}" |
316 @{ML_response [display,gray] "make_wrong_imp @{term S} @{term T} @{typ nat}" |
315 "Const \<dots> $ |
317 "Const \<dots> $ |
316 Abs (\"x\", \<dots>, |
318 Abs (\"x\", \<dots>, |
335 |
337 |
336 @{ML_response_fake [display,gray] "@{const_name \"Nil\"}" "List.list.Nil"} |
338 @{ML_response_fake [display,gray] "@{const_name \"Nil\"}" "List.list.Nil"} |
337 |
339 |
338 (FIXME: Is it useful to explain @{text "@{const_syntax}"}?) |
340 (FIXME: Is it useful to explain @{text "@{const_syntax}"}?) |
339 |
341 |
340 Similarly, types can be constructed manually. For example a function type |
342 Similarly, one can construct types manually. For example the function returning |
341 can be constructed as follows: |
343 a function type is as follows: |
342 |
344 |
343 *} |
345 *} |
344 |
346 |
345 ML{*fun make_fun_type tau1 tau2 = Type ("fun",[tau1,tau2]) *} |
347 ML{*fun make_fun_type tau1 tau2 = Type ("fun",[tau1,tau2]) *} |
346 |
348 |
386 term is well-formed, or type-checks, relative to a theory. |
388 term is well-formed, or type-checks, relative to a theory. |
387 Type-checking is done via the function @{ML cterm_of}, which converts |
389 Type-checking is done via the function @{ML cterm_of}, which converts |
388 a @{ML_type term} into a @{ML_type cterm}, a \emph{certified} term. |
390 a @{ML_type term} into a @{ML_type cterm}, a \emph{certified} term. |
389 Unlike @{ML_type term}s, which are just trees, @{ML_type |
391 Unlike @{ML_type term}s, which are just trees, @{ML_type |
390 "cterm"}s are abstract objects that are guaranteed to be |
392 "cterm"}s are abstract objects that are guaranteed to be |
391 type-correct, and that can only be constructed via the ``official |
393 type-correct, and they can only be constructed via the ``official |
392 interfaces''. |
394 interfaces''. |
393 |
395 |
394 Type-checking is always relative to a theory context. For now we use |
396 Type-checking is always relative to a theory context. For now we use |
395 the @{ML "@{theory}"} antiquotation to get hold of the current theory. |
397 the @{ML "@{theory}"} antiquotation to get hold of the current theory. |
396 For example we can write |
398 For example we can write |
399 |
401 |
400 or use the antiquotation |
402 or use the antiquotation |
401 |
403 |
402 @{ML_response_fake [display,gray] "@{cterm \"(a::nat) + b = c\"}" "a + b = c"} |
404 @{ML_response_fake [display,gray] "@{cterm \"(a::nat) + b = c\"}" "a + b = c"} |
403 |
405 |
404 Attempting |
406 Attempting to obtain the certified term for |
405 |
407 |
406 @{ML_response_fake_both [display,gray] "@{cterm \"1 + True\"}" "Type unification failed \<dots>"} |
408 @{ML_response_fake_both [display,gray] "@{cterm \"1 + True\"}" "Type unification failed \<dots>"} |
407 |
409 |
408 yields an error. A slightly more elaborate example is |
410 yields an error (since the term is not typable). A slightly more elaborate |
|
411 example that type-checks is |
|
412 |
409 |
413 |
410 @{ML_response_fake [display,gray] |
414 @{ML_response_fake [display,gray] |
411 "let |
415 "let |
412 val natT = @{typ \"nat\"} |
416 val natT = @{typ \"nat\"} |
413 val zero = @{term \"0::nat\"} |
417 val zero = @{term \"0::nat\"} |
425 |
429 |
426 section {* Theorems *} |
430 section {* Theorems *} |
427 |
431 |
428 text {* |
432 text {* |
429 Just like @{ML_type cterm}s, theorems are abstract objects of type @{ML_type thm} |
433 Just like @{ML_type cterm}s, theorems are abstract objects of type @{ML_type thm} |
430 that can only be built by going through interfaces. As a consequence of this is that |
434 that can only be built by going through interfaces. As a consequence, every proof |
431 every proof is correct by construction (FIXME reference LCF-philosophy) |
435 in Isabelle is correct by construction (FIXME reference LCF-philosophy) |
432 |
436 |
433 To see theorems in ``action'', let us give a proof for the following statement |
437 To see theorems in ``action'', let us give a proof on the ML-level for the following |
|
438 statement: |
434 *} |
439 *} |
435 |
440 |
436 lemma |
441 lemma |
437 assumes assm\<^isub>1: "\<And>(x::nat). P x \<Longrightarrow> Q x" |
442 assumes assm\<^isub>1: "\<And>(x::nat). P x \<Longrightarrow> Q x" |
438 and assm\<^isub>2: "P t" |
443 and assm\<^isub>2: "P t" |
439 shows "Q t" (*<*)oops(*>*) |
444 shows "Q t" (*<*)oops(*>*) |
440 |
445 |
441 text {* |
446 text {* |
442 on the ML-level:\footnote{Note that @{text "|>"} is reverse |
447 The corresponding ML-code is as follows:\footnote{Note that @{text "|>"} is reverse |
443 application. See Section~\ref{sec:combinators}.} |
448 application. See Section~\ref{sec:combinators}.} |
444 |
449 |
445 @{ML_response_fake [display,gray] |
450 @{ML_response_fake [display,gray] |
446 "let |
451 "let |
447 val thy = @{theory} |
452 val thy = @{theory} |
490 section {* Theorem Attributes *} |
495 section {* Theorem Attributes *} |
491 |
496 |
492 section {* Operations on Constants (Names) *} |
497 section {* Operations on Constants (Names) *} |
493 |
498 |
494 text {* |
499 text {* |
495 (FIXME how can I extract the constant name without the theory name etc) |
500 |
|
501 @{ML_response [display] "Sign.base_name \"List.list.Nil\"" "\"Nil\""} |
|
502 |
496 *} |
503 *} |
497 |
504 |
498 section {* Combinators\label{sec:combinators} *} |
505 section {* Combinators\label{sec:combinators} *} |
499 |
506 |
500 text {* |
507 text {* |
501 Perhaps one of the most puzzling aspects for a beginner when reading at |
508 Perhaps one of the most puzzling aspects for a beginner when reading |
502 existing Isabelle code is the liberal use of combinators. At first they |
509 existing Isabelle code is the liberal use of combinators. At first they |
503 seem to obstruct the comprehension of the code, but after getting familiar |
510 seem to obstruct the comprehension of the code, but after getting familiar |
504 with them they actually ease the reading and also the programming. |
511 with them they actually ease the reading and also the programming. |
505 |
512 |
506 \begin{readmore} |
513 \begin{readmore} |
507 The most frequently used combinator are defined in the files @{ML_file "Pure/library.ML"} |
514 The most frequently used combinator are defined in the files @{ML_file "Pure/library.ML"} |
508 and @{ML_file "Pure/General/basics.ML"}. |
515 and @{ML_file "Pure/General/basics.ML"}. |
509 \end{readmore} |
516 \end{readmore} |
510 |
517 |
511 The simplest combinator is @{ML I} which is just the identidy function. |
518 The simplest combinator is @{ML I} which is just the identity function. |
512 *} |
519 *} |
513 |
520 |
514 ML{*fun I x = x*} |
521 ML{*fun I x = x*} |
515 |
522 |
516 text {* Another frequently used combinator is @{ML K} *} |
523 text {* Another frequently used combinator is @{ML K} *} |
519 |
526 |
520 text {* |
527 text {* |
521 which ``wraps'' a function around the argument @{text "x"}. This function |
528 which ``wraps'' a function around the argument @{text "x"}. This function |
522 ignores its argument. |
529 ignores its argument. |
523 |
530 |
524 @{ML "(op |>)"} |
531 The next combinator is reverse application defined as |
525 *} |
532 *} |
526 |
533 |
527 ML{*fun x |> f = f x*} |
534 ML{*fun x |> f = f x*} |
528 |
535 |
|
536 text {* The purpose of this combinator is to implement functions in a |
|
537 ``waterfall fashion''. Consider for example the function *} |
|
538 |
|
539 ML %linenumbers{*fun inc_by_five x = |
|
540 x |> (fn x => x + 1) |
|
541 |> (fn x => (x, x)) |
|
542 |> fst |
|
543 |> (fn x => x + 4)*} |
|
544 |
|
545 text {* |
|
546 which increments the argument @{text x} by 5. It does this by first incrementing |
|
547 the argument by 1 (Line 2); then storing the result in a pair (Line 3); taking |
|
548 the first component of the pair (Line 4) and finally incrementing the first |
|
549 component by 4 (Line 5). This kind of cascading manipulations of values is quite |
|
550 common when extending theories (for example by adding a definition, followed by |
|
551 lemmas and so on). Writing the function @{ML inc_by_five} using the reverse |
|
552 application is much clearer than writing |
|
553 *} |
|
554 |
|
555 ML{*fun inc_by_five x = fst ((fn x => (x, x)) (x + 1)) + 4*} |
|
556 |
|
557 text {* or *} |
|
558 |
|
559 ML{*fun inc_by_five x = |
|
560 ((fn x => x + 4) o fst o (fn x => (x, x)) o (fn x => x + 1)) x*} |
|
561 |
|
562 text {* and much more economical than *} |
|
563 |
|
564 ML{*fun inc_by_five x = |
|
565 let val y1 = x + 1 |
|
566 val y2 = (y1, y1) |
|
567 val y3 = fst y2 |
|
568 val y4 = y3 + 4 |
|
569 in y4 end*} |
|
570 |
|
571 text {* |
|
572 Similarly, the combinator @{ML "(op #>)"} is the reverse function |
|
573 composition. It allows us to define functions as follows |
|
574 *} |
|
575 |
|
576 ML{*val inc_by_six = |
|
577 (fn x => x + 1) |
|
578 #> (fn x => x + 2) |
|
579 #> (fn x => x + 3)*} |
|
580 |
|
581 text {* |
|
582 which is the function composed of first the increment-by-one function and then |
|
583 increment-by-two, followed by increment-by-three. Applying 6 to this function |
|
584 yields |
|
585 |
|
586 @{ML_response [display,gray] "inc_by_six 6" "12"} |
|
587 |
|
588 as expected. |
|
589 |
|
590 The remaining combinators add convenience for the ``waterfall method'' |
|
591 of writing functions. The combinator @{ML tap} allows one to get |
|
592 hold of a intermediate result for some side-calculations. For |
|
593 example the function *} |
|
594 |
|
595 ML{*fun inc_by_three x = |
|
596 x |> (fn x => x + 1) |
|
597 |> tap (fn x => tracing (makestring x)) |
|
598 |> (fn x => x + 2)*} |
|
599 |
|
600 text {* increments the argument first by one and then by two. In the middle, |
|
601 however, it prints the ``plus-one'' intermediate result inside the |
|
602 tracing buffer. |
|
603 |
|
604 The combinator @{ML "(op `)"} is similar, but applies a function to the value |
|
605 and returns the result together with the original value as pair. For example |
|
606 the following function takes @{text x} then increments @{text x} and returns |
|
607 the pair @{ML "(x + 1,x)" for x}. It then increments the right-hand component |
|
608 of the pair. |
|
609 *} |
|
610 |
|
611 ML{*fun inc_as_pair x = |
|
612 x |> `(fn x => x + 1) |
|
613 |> (fn (x, y) => (x, y + 1))*} |
|
614 |
|
615 text {* |
|
616 The combinators @{ML "(op |>>)"} and @{ML "(op ||>)"} are defined for |
|
617 functions manipulating pairs. The first applies the function to |
|
618 the first component of the pair: |
|
619 *} |
|
620 |
|
621 ML{*fun (x, y) |>> f = (f x, y)*} |
|
622 |
|
623 text {* |
|
624 and the second combinator to the second component: |
|
625 *} |
|
626 |
|
627 ML{*fun (x, y) ||> f = (x, f y)*} |
|
628 |
|
629 |
529 end |
630 end |