1\chapter{Esempio: il Teorema di Euclide} 2\label{chap:euclid} 3 4\setcounter{sessioncount}{0} 5 6In questo capitolo, dimostriamo in \holn{} che per ogni numero, c'� un 7numero primo che � pi� grande, cio�, che i numeri primi formano una 8sequenza infinita. Questa dimostrazione � stata estratta e adattata da un 9pi� ampio esempio, dovuto a John Harrison, in cui egli dimostrava il caso 10$n = 4$ dell'ultimo teorema di Fermat. Lo sviluppo della dimostrazione ha lo scopo 11di servire come un'introduzione all'esecuzione di dimostrazioni interattive di alto livello 12in \holn\footnote{Le dimostrazioni discusse di sotto si possono trovare in 13\texttt{examples/euclid.sml} della distribuzione \HOL{}.}. 14Molti dei dettagli possono essere difficili da cogliere per il lettore alle prime armi; 15ciononostante, si raccomanda di seguire l'esempio in modo completo 16al fine di ottenere una vera sensazione dell'uso di \HOL{} per dimostrare teoremi non-banali. 17 18Alcuni tutorial sulla descrizione di sistemi di dimostrazione, mostrano il sistema mentre esegue 19incredibili gesta di dimostrazione automatica di teoremi. In questo esempio, \textit{non} 20abbiamo seguito questo approccio; piuttosto, cerchiamo di mostrare come si affronta 21nella realt� il problema di dimostrare teoremi in \holn{}: quando 22� possibile pi� di un modo per dimostrare qualcosa, considereremo 23le scelte; quando sorge una difficolt�, tenteremo di spiegare come affrontare 24il problema in modo chiaro. 25 26Si `guida' \holn{} interagendo con il loop interattivo ML. In questo 27stile interattivo, si eseguono chiamate a funzioni ML per richiamare 28un contesto logico gi� stabilito, ad esempio, attraverso \ml{load}; per definire 29nuovi concetti, ad esempio, attraverso \ml{Hol\_datatype}, \ml{Define}, e \ml{Hol\_reln}; 30e per eseguire dimostrazioni usando l'interfaccia goalstack, e 31gli strumenti di dimostrazione da \ml{bossLib} (o se essi falliscono, dalle 32librerie di basso livello). 33 34Cominciamo. Per prima cosa, avviamo il sistema, con il comando \ml{<holdir>/bin/hol}. 35Quindi con ``\ml{open}'' apriamo la teoria aritmetica; questo significa che tutti i binding \ML{} 36dalla teoria \HOL{} sono resi disponibili al loop interattivo. 37\begin{session} 38\begin{verbatim} 39- open arithmeticTheory; 40 ... 41\end{verbatim} 42\end{session} 43Ora iniziamo la formalizzazione. Al fine di definire il concetto di 44numero primo, abbiamo prima bisogno di definire la relazione di \emph{divisibilit�}: 45 46\begin{session} 47\begin{verbatim} 48- val divides_def = Define `divides a b = ?x. b = a * x`; 49 50Definition has been stored under "divides_def". 51> val divides_def = |- !a b. divides a b = ?x. b = a * x : thm 52\end{verbatim} 53\end{session} 54 55La definizione � aggiunta alla teoria corrente con il nome 56\ml{divides\_def}, ed � anche restituita dall'invocazione di 57\ml{Define}. Approfittiamo di questo ed effettuiamo un binding del nome 58\ML{} \ml{divides\_def} alla definizione. Nel modo usuale di 59interagire con \HOL, un tale binding \ML{} � fatto per ogni 60definizione e teorema (utile) dimostrato: l'ambiente \ML{} viene 61cos� usato come un luogo conveniente per mantenere definizioni e teoremi per 62un futuro riferimento nella sessione. 63 64Vogliamo trattare \ml{divides} come un infisso (non-associativo): 65\begin{session} 66\begin{verbatim} 67- set_fixity "divides" (Infix(NONASSOC, 450)); 68\end{verbatim} 69\end{session} 70Poi definiamo la propriet� di essere un numero \emph{primo}: un numero $p$ � 71primo se e solo se non � uguale a $1$ e non ha altri divisori oltre 72$1$ e s� stesso: 73 74\begin{session} 75\begin{verbatim} 76- val prime_def = 77 Define `prime p = ~(p=1) /\ !x. x divides p ==> (x=1) \/ (x=p)`; 78 79Definition has been stored under "prime_def". 80> val prime_def = 81 |- !p. prime p = ~(p = 1) /\ !x. x divides p ==> (x = 1) \/ (x = p) 82 : thm 83\end{verbatim} 84\end{session} 85 86Questo conclude le definizioni da fare. Ora dobbiamo ``solo'' dimostrare 87che ci sono infiniti numeri primi. Se fossimo arrivati ad affrontare questo 88problema senza un background, allora saremmo costretti a passare per un processo 89non completamente chiaro e spesso tremendamente difficile di ricerca dei giusti lemmi 90richiesti per dimostrare il nostro teorema desiderato\footnote{Questo naturalmente � un 91problema generale quando si affronta qualsiasi tipo di dimostrazione.}. Fortunatamente, stiamo 92lavorando a partire da un dimostrazione gi� completata e possiamo dedicarci al problema 93decisamente pi� semplice di spiegare come dimostrare i teoremi richiesti. 94 95\paragraph{Strumenti di dimostrazione} 96Lo sviluppo illustrer� che c'� spesso pi� di un modo di 97affrontare una dimostrazione HOL, persino quando si ha in mente un'unica dimostrazione 98(informale). In questo esempio, spesso \emph{troviamo} dimostrazioni usando 99la tattica di riscrittura \ml{RW\_TAC} per espandere le definizioni ed eseguire semplificazioni 100di base, riducendo spesso un goal alla sua essenza. 101\begin{session} 102\begin{verbatim} 103RW_TAC; 104val it = fn :simpset -> thm list -> term list * term -> 105 (term list * term) list * (thm list -> thm) 106\end{verbatim} 107\end{session} 108Il tipo ML di \ml{RW\_TAC} � 109\ml{:simpset -> thm list -> tactic}\footnote{Sfortunatamente, il sistema MoscowML non stampa 110il tipo delle tattiche nella sua forma abbreviata.}. 111Quando \ml{RW\_TAC} � applicata a un \textit{simpset}---per questo esempio sar� 112sempre \ml{arith\_ss}---e a una lista di teoremi, i 113teoremi saranno aggiunti al simpset come regole di riscrittura aggiuntive. 114Vedremo che \ml{arith\_ss} � anche informato in qualche modo circa 115l'aritmetica\footnote{Specialmente l'aritmetica lineare: formule puramente 116universali, che coinvolgono gli operatori {\tt SUC}, $+$, $-$, letterali 117numerici, $<$, $\leq$, $>$, $\geq$, $=$, e la moltiplicazione per letterali 118numerici}. 119A volte la semplificazione con \ml{RW\_TAC} dimostra il goal immediatamente. 120Spesso comunque, ci rimane un goal che richiede un p� di studio prima di 121realizzare quali lemmi sono necessari per concludere la dimostrazione. Una volta che questi lemmi 122sono stati dimostrati, o individuati nelle teorie progenitrici, 123\ml{METIS\_TAC}\footnote{\ml{METIS\_TAC} 124esegue una ricerca della dimostrazione al primo ordine nello stile della risoluzione.} pu� 125essere invocata con essi, con la speranza che essa individuer� le istanziazioni 126corrette necessarie per concludere la dimostrazione. Si noti che queste due operazioni, 127la semplificazione e la ricerca automatica di una dimostrazione nello stile della risoluzione, non saranno sufficienti per 128eseguire tutte le dimostrazioni in questo esempio: in particolare, il nostro sviluppo, avr� 129anche bisogno dell'analisi dei casi e dell'induzione. 130 131\paragraph{Trovare i teoremi} 132Questo fa sorgere la seguente domanda: come si trovano i giusti lemmi e 133le regole di riscrittura da usare? Questo � piuttosto problematico, specialmente dal momento che il numero di 134teorie progenitrici, e di teoremi al loro interno, � grande. Ci sono molte 135possibilit�. 136\begin{itemize} 137\item Si pu� usare il sistema di help per cercare definizioni e 138teoremi, cos� come procedure di dimostrazione; per esempio, un'invocazione di 139{\small 140\begin{verbatim} 141 help "arithmeticTheory" 142\end{verbatim}} 143mostrer� tutte le definizioni e i teoremi che sono stati archiviati nella 144teoria dell'aritmetica. Comunque, bisogna conoscere il nome completo dell'elemento 145che si sta cercando prima che il sistema di help sia utile, cos� i due 146seguenti strumenti di ricerca sono spesso pi� utili. 147\item \verb+DB.match+ permette l'uso di pattern per individuare il 148teorema cercato. Sar� restituito qualunque teorema archiviato che ha un'istanza del pattern 149come un sotto termine. 150\item \verb+DB.find+ user� frammenti dei nomi come chiavi con cui 151cercare l'informazione 152\end{itemize} 153 154\paragraph{Composizione di tattiche} 155Una volta che � stata trovata una dimostrazione di una proposizione, � d'abitudine, bench� 156non necessario, avviare un processo di \emph{revisione}, in cui la 157sequenza di tattiche originaria � composta in un'unica tattica. A volte, 158la tattica risultante � molto pi� breve, e in un certo senso pi� gradevole 159da un punto di vista estetico. Alcuni utenti spendono un bel p� di tempo per raffinare queste tattiche, 160nonostante non sembri esserci un reale maggior beneficio nel fare questo, dal momento che esse 161sono ricette di dimostrazione \emph{ad hoc}, una per ciascun teorema. Nel 162seguito, mostreremo in pochi casi come questo viene fatto. 163 164\section{Divisibilit�} 165 166Iniziamo dimostrando un numero di teoremi circa la relazione 167\verb+divides+. Vedremo che ciascuno di questi teoremi iniziali pu� essere 168dimostrato con una singola invocazione di \ml{METIS\_TAC}. Sia \ml{RW\_TAC} 169sia \ml{METIS\_TAC} sono ragionatori piuttosto potenti, e la scelta di un 170ragionatore in una situazione particolare � una questione di esperienza. La 171ragione principale per cui \ml{METIS\_TAC} funziona cos� bene � che \verb+divides+ 172� definita per mezzo di un quantificatore esistenziale, e \ml{METIS\_TAC} 173� piuttosto buono per istanziare in modo automatico gli esistenziali nel 174corso di una dimostrazione. Per un semplice esempio, si consideri la dimostrazione di $\forall x.\ 175x\; \mathtt{divides}\; 0$. Si inserisce una nuova proposizione da dimostrare 176attraverso ``\ml{g}'', che avvia un nuovo goalstack. 177 178\begin{session} 179\begin{verbatim} 180- g `!x. x divides 0`; 181 182> val it = 183 Proof manager status: 1 proof. 184 1. Incomplete: 185 Initial goal: 186 !x. x divides 0 187 188 : proofs 189\end{verbatim} 190\end{session} 191Il manager di dimostrazione ci dice che c'� soltanto una dimostrazione da gestire, e 192ripete il goal dato. Ora espandiamo la definizione di 193\verb+divides+. Si noti che ha luogo un'$\alpha$-conversione al fine di 194mantenere distinta la $x$ del goal e la $x$ nella definizione di 195\ml{divides}: 196\begin{session} 197\begin{verbatim} 198- e (RW_TAC arith_ss [divides_def]); 199 200OK.. 2011 subgoal: 202> val it = 203 ?x'. (x = 0) \/ (x' = 0) 204\end{verbatim} 205\end{session} 206E' naturalmente piuttosto facile istanziare il quantificatore esistenziale a 207mano. 208\begin{session} 209\begin{verbatim} 210- e (EXISTS_TAC ``0``); 211 212OK.. 2131 subgoal: 214> val it = 215 (x = 0) \/ (0 = 0) 216\end{verbatim} 217\end{session} 218Poi un passo di semplificazione conclude la dimostrazione. 219\begin{session} 220\begin{verbatim} 221- e (RW_TAC arith_ss []); 222OK.. 223 224Goal proved. 225|- (x = 0) \/ (0 = 0) 226 227Goal proved. 228|- ?x'. (x = 0) \/ (x' = 0) 229> val it = 230 Initial goal proved. 231 |- !x. x divides 0 232\end{verbatim} 233\end{session} 234 235Cosa � appena successo qui? L'applicazione di \ml{RW\_TAC} al goal 236lo ha decomposto in una lista vuota di subgoal; in altre parole, il goal � stato 237dimostrato da \ml{RW\_TAC}. Una volta che il goal � stato dimostrato, � tirato fuori 238dal goalstack, stampato a video, e il teorema diventa 239disponibile per l'uso al livello dello stack. Quando tutti i subgoal 240richiesti da \textit{quel} livello sono stati dimostrati, anche il goal corrispondente a 241quel livello pu� essere dimostrato. Questo processo di `svolgimento' continua fino a quando 242lo stack � vuoto, o fino a quando raggiunge un goal con pi� di un subgoal 243non dimostrato rimanente. Questo processo pu� essere difficile da 244visualizzare,\footnote{Forse per il fatto che abbiamo usato uno stack per implementare quello 245che teoricamente � un albero!} ma ci� non importa, dal momento che il goalstack � stato 246scritto espressamente per permettere all'utente d'ignorare tali dettagli. 247 248Se le tre interazioni sono combinate insieme con \ml{THEN} per 249formare una singola tattica, possiamo provare la dimostrazione 250dall'inizio (usando la funzione \ml{restart}) e questa volta richieder� 251soltanto un unico passo: 252\begin{session} 253\begin{verbatim} 254- restart(); 255> ... 256 257- e (RW_TAC arith_ss [divides_def] THEN EXISTS_TAC ``0`` 258 THEN RW_TAC arith_ss []); 259OK.. 260 261> val it = 262 Initial goal proved. 263 |- !x. x divides 0 264\end{verbatim} 265\end{session} 266Abbiamo visto un modo di dimostrare il teorema. Comunque, come menzionato 267in precedenza, c'� un altro modo: si potrebbe lasciare che \ml{METIS\_TAC} espanda la 268definizione di \ml{divides} e trovi l'istanziazione richiesta per 269\verb+x'+ dal teorema \ml{MULT\_CLAUSES}\footnote{Potreste 270 voler provare a digitare \ml{MULT\_CLAUSES} nel loop interativo 271 per vedere esattamente cosa esso afferma.}. 272\begin{session} 273\begin{verbatim} 274- restart(); 275> ... 276 277- e (METIS_TAC [divides_def, MULT_CLAUSES]); 278OK.. 279metis: r[+0+10]+0+0+0+1+2# 280> val it = 281 Initial goal proved. 282 |- !x. x divides 0 283\end{verbatim} 284\end{session} 285Mentre lavora, \ml{METIS\_TAC} stampa a video alcune diagnostiche 286possibilmente interessanti. In ogni caso, avendo eseguito la nostra dimostrazione all'interno del pacchetto goalstack, 287 ora vogliamo avere accesso al valore del teorema che abbiamo 288 dimostrato. Per far questo usiamo la funzione \ml{top\_thm}, e quindi 289 usiamo \ml{drop} per svuotare lo stack: 290\begin{session} 291\begin{verbatim} 292- val DIVIDES_0 = top_thm(); 293 294> val DIVIDES_0 = |- !x. x divides 0 : thm 295 296- drop(); 297OK.. 298> val it = There are currently no proofs. : proofs 299\end{verbatim} 300\end{session} 301 302Abbiamo usato \ml{METIS\_TAC} in questo modo per dimostrare la seguente 303collezione di teoremi circa \ml{divides}. Come menzionato in precedenza, i 304teoremi forniti a \ml{METIS\_TAC} nelle seguenti dimostrazioni (di solito) non 305provengono dal nulla: in molti casi � stato fatto un qualche lavoro esplorativo 306con \ml{RW\_TAC} per espandere le definizioni e vedere quali lemmi sarebbero 307stati richiesti da \ml{METIS\_TAC}. 308 309\begin{description} 310\label{euclid:extra-proofs} 311\item [\small{({\it DIVIDES\_0\/})}] 312\begin{tabular}[t]{l} 313\verb+!x. x divides 0+ \\ \hline 314 \verb+METIS_TAC [divides_def, MULT_CLAUSES]+ 315\end{tabular} 316 317\item[\small{({\it DIVIDES\_ZERO\/})}] 318\begin{tabular}[t]{l} 319\verb+!x. 0 divides x = (x = 0)+ \\ \hline 320 \verb+METIS_TAC [divides_def, MULT_CLAUSES]+ 321\end{tabular} 322 323\item[\small{({\it DIVIDES\_ONE\/})}] 324\begin{tabular}[t]{l} 325\verb+!x. x divides 1 = (x = 1)+ \\ \hline 326 \verb+METIS_TAC [divides_def, MULT_CLAUSES, MULT_EQ_1]+ 327\end{tabular} 328 329\item[\small{({\it DIVIDES\_REFL\/})}] 330\begin{tabular}[t]{l} 331\verb+!x. x divides x+ \\ \hline 332 \verb+METIS_TAC [divides_def, MULT_CLAUSES]+ \\ 333\end{tabular} 334 335\item[\small{({\it DIVIDES\_TRANS\/})}] 336\begin{tabular}[t]{l} 337\verb+!a b c. a divides b /\ b divides c ==> a divides c+ \\ \hline 338 \verb+METIS_TAC [divides_def, MULT_ASSOC]+ \\ 339\end{tabular} 340\item[\small{({\it DIVIDES\_ADD\/})}] 341\begin{tabular}[t]{l} 342\verb|!d a b. d divides a /\ d divides b ==> d divides (a+b)| \\ \hline 343 \verb|METIS_TAC [divides_def,LEFT_ADD_DISTRIB]| 344\end{tabular} 345 346\item[\small{({\it DIVIDES\_SUB\/})}] 347\begin{tabular}[t]{l} 348\verb+!d a b. d divides a /\ d divides b ==> d divides (a-b)+ \\ \hline 349 \verb+METIS_TAC [divides_def, LEFT_SUB_DISTRIB]+ \\ 350\end{tabular} 351 352\item[\small{({\it DIVIDES\_ADDL\/})}] 353\begin{tabular}[t]{l} 354\verb|!d a b. d divides a /\ d divides (a+b) ==> d divides b| \\ \hline 355 \verb+METIS_TAC [ADD_SUB, ADD_SYM, DIVIDES_SUB]+ \\ 356\end{tabular} 357 358\item[\small{({\it DIVIDES\_LMUL\/})}] 359\begin{tabular}[t]{l} 360\verb+!d a x. d divides a ==> d divides (x * a)+ \\ \hline 361 \verb+METIS_TAC [divides_def, MULT_ASSOC, MULT_SYM]+ \\ 362\end{tabular} 363 364\item[\small{({\it DIVIDES\_RMUL\/})}] 365\begin{tabular}[t]{l} 366\verb+!d a x. d divides a ==> d divides (a * x)+ \\ \hline 367 \verb+METIS_TAC [MULT_SYM, DIVIDES_LMUL]+ \\ 368\end{tabular} 369 370\end{description} 371 372\noindent Assumeremo che le dimostrazioni di sopra siano state eseguite, e 373che gli appropriati nomi ML siano stati dati a tutti i teoremi. 374Ora affrontiamo un lemma circa la divisibilit� che non soccombe a una 375singola invocazione di \ml{METIS\_TAC}: 376\begin{description} 377\item [\small{({\it DIVIDES\_LE\/})}] 378\begin{tabular}[t]{l} 379\verb+!m n. m divides n ==> m <= n \/ (n = 0)+ \\ \hline 380\verb+RW_TAC arith_ss [divides_def]+ \\ 381\verb+ THEN Cases_on `x`+ \\ 382\verb+ THEN RW_TAC arith_ss [MULT_CLAUSES]+ \\ 383\end{tabular} 384\end{description} 385Vediamo come questo � dimostrato. Il modo pi� semplice � di iniziare a semplificare 386con la definizione di \ml{divides}: 387\begin{session} 388\begin{verbatim} 389- g `!m n . m divides n ==> m <= n \/ (n = 0)`; 390> ... 391 392- e (RW_TAC arith_ss [divides_def]); 393 3941 subgoal: 395> val it = 396 m <= m * x \/ (m * x = 0) 397\end{verbatim} 398\end{session} 399 400Considerando il goal, di base abbiamo tre possibilit�: (1) trovare una 401collezione di lemmi che insieme implicano il goal e usare 402\ml{METIS\_TAC}; (2) fare un case split su $m$; oppure (3) fare un case split su 403$x$. La prima non sembra semplice, dal momento che il goal in realt� 404non calza nella `forma' di un qualsiasi teorema pre-dimostrato di cui l'autore sia a 405conoscenza. Bench� l'opzione (2) sar� rigettata alla fine, proviamola 406comunque. Per eseguire il case split, usiamo \verb+Cases_on+, che sta 407per ``trova il termine dato nel goal ed esegui un'analisi dei casi sulle 408possibilit� di costruzione previste dal costruttore del suo datatype'' [corrisponde al pattern matching di ML (ndt)]. Dal momento che 409l'occorrenza di $m$ nel goal ha il tipo $num$, i casi considerati saranno 410se $m$ � $0$ o un successore. 411\begin{session} 412\begin{verbatim} 413- e (Cases_on `m`); 414OK.. 4152 subgoals: 416> val it = 417 SUC n <= SUC n * x \/ (SUC n * x = 0) 418 419 0 <= 0 * x \/ (0 * x = 0) 420\end{verbatim} 421\end{session} 422\noindent Il primo subgoal (l'ultimo stampato) � banale: 423 424\begin{session} 425\begin{verbatim} 426- e (RW_TAC arith_ss []); 427OK.. 428 429Goal proved. 430 ... 431 432Remaining subgoals: 433> val it = 434 SUC n <= SUC n * x \/ (SUC n * x = 0) 435\end{verbatim} 436\end{session} 437\noindent Proviamo \ml{RW\_TAC} di nuovo: 438\begin{session} 439\begin{verbatim} 440- e (RW_TAC arith_ss []); 441OK.. 4421 subgoal: 443> val it = 444 SUC n <= x * SUC n \/ (x = 0) 445\end{verbatim} 446\end{session} 447Il disgiunto a destra � stato semplificato; comunque, il disgiunto a sinistra ha 448fallito di espandere la definizione della moltiplicazione nell'espressione 449$\mathtt{SUC}\ n * x$, cosa che sarebbe stata conveniente. Di fatto l'ha cambiata 450in $x * \mathtt{SUC}\ n$, che non � conveniente. 451Perch�, visto che si suppone che \verb+arith_ss+ e di conseguenza \ml{RW\_TAC} siano esperte 452nell'aritmetica? La risposta � duplice: primo, le clausole ricorsive per l'addizione e la 453moltiplicazione non sono in \verb+arith_ss+ perch� una loro applicazione senza controllo 454da parte del sistema di riscrittura sembra che, in generale, renda alcune 455dimostrazioni \emph{pi�} complicate, piuttosto che pi� semplici; in secondo luogo, il semplificatore 456riorganizzer� i termini aritmetici per rendere pi� semplici alcune dimostrazioni automatiche. Cos� 457l'assenza delle clausole ricorsive per la moltiplicazione 458significa che $\mathtt{SUC}\ n * x$ non si espande a $(n * x) + x$; 459piuttosto, la riorganizzazione porta a $x * \mathtt{SUC}\; n$. OK, aggiungiamo 460la definizione della moltiplicazione. Questo rivela un nuovo problema: come 461individuare questa definizione. La funzione 462\begin{holboxed} 463\begin{verbatim} 464 DB.match : string list -> term 465 -> ((string * string) * (thm * class)) list 466\end{verbatim} 467\end{holboxed} 468 469\noindent 470� spesso utile a questo scopo. Essa prende una lista di nomi di teorie, e 471un pattern, e cerca nella lista delle teorie un teorema, 472una definizione, o un assioma che ha un'istanza del pattern come sotto termine. 473Se la lista dei nomi di teorie � vuota, allora sono incluse nella ricerca 474tutte le teorie caricate. Cerchiamo nella teoria dell'aritmetica il 475sotto termine che deve essere riscritto. 476 477\begin{session} 478\begin{verbatim} 479- DB.match ["arithmetic"] ``SUC n * x``; 480 481> val it = 482 [(("arithmetic", "FACT"), 483 (|- (FACT 0 = 1) /\ !n. FACT (SUC n) = SUC n * FACT n, Def)), 484 (("arithmetic", "LESS_MULT_MONO"), 485 (|- !m i n. SUC n * m < SUC n * i = m < i, Thm)), 486 (("arithmetic", "MULT"), 487 (|- (!n. 0 * n = 0) /\ !m n. SUC m * n = m * n + n, Def)), 488 (("arithmetic", "MULT_CLAUSES"), 489 (|- !m n. 490 (0 * m = 0) /\ (m * 0 = 0) /\ (1 * m = m) /\ (m * 1 = m) /\ 491 (SUC m * n = m * n + n) /\ (m * SUC n = m + m * n), Thm)), 492 (("arithmetic", "MULT_LESS_EQ_SUC"), 493 (|- !m n p. m <= n = SUC p * m <= SUC p * n, Thm)), 494 (("arithmetic", "MULT_MONO_EQ"), 495 (|- !m i n. (SUC n * m = SUC n * i) = m = i, Thm)), 496 (("arithmetic", "ODD_OR_EVEN"), 497 (|- !n. ?m. (n = SUC (SUC 0) * m) \/ (n = SUC (SUC 0) * m + 1), Thm))] 498 : ... 499\end{verbatim} 500\end{session} 501 502Per alcuni, questo restituisce un p� troppa informazione; comunque, possiamo 503focalizzare la ricerca stabilendo che il pattern appaia come una regola 504di riscrittura: 505 506\begin{session} 507\begin{verbatim} 508- DB.match [] ``SUC n * x = M``; 509 510> val it = 511 [(("arithmetic", "MULT"), 512 (|- (!n. 0 * n = 0) /\ !m n. SUC m * n = m * n + n, Def)), 513 (("arithmetic", "MULT_CLAUSES"), 514 (|- !m n. 515 (0 * m = 0) /\ (m * 0 = 0) /\ (1 * m = m) /\ (m * 1 = m) /\ 516 (SUC m * n = m * n + n) /\ (m * SUC n = m + m * n), Thm)), 517 (("arithmetic", "MULT_MONO_EQ"), 518 (|- !m i n. (SUC n * m = SUC n * i) = m = i, Thm))] : ... 519\end{verbatim} 520\end{session} 521 522Sia {\small\verb+arithmeticTheory.MULT+} sia 523{\small\verb+arithmeticTheory.MULT_CLAUSES+} sarebbero accettabili; 524scegliamo l'ultima. 525 526\begin{session} 527\begin{verbatim} 528- b(); 529 ... 530 531e (RW_TAC arith_ss [MULT_CLAUSES]); 532 533OK.. 5341 subgoal: 535> val it = 536 SUC n <= x + n * x \/ (x = 0) 537\end{verbatim} 538\end{session} 539Ora vediamo che, al fine di fare progressi nella dimostrazione, dovremo fare 540un case split su $x$ comunque, e che avremmo dovuto fare lo split su di esso 541fin dall'inizio. Di conseguenza facciamo un backup. Dovremo fare un backup (undo) tre volte. 542\begin{session} 543\begin{verbatim} 544- b(); 545> val it = 546 SUC n <= SUC n * x \/ (SUC n * x = 0) 547 548- b(); 549> val it = 550 SUC n <= SUC n * x \/ (SUC n * x = 0) 551 552 553 0 <= 0 * x \/ (0 * x = 0) 554 555- b(); 556> val it = 557 m <= m * x \/ (m * x = 0) 558\end{verbatim} 559\end{session} 560 561Ora possiamo andare avanti e fare un'analisi dei casi su $x$. Eseguiremo anche\linebreak 562l'invocazione a una tattica composta, dal momento che sappiamo gi� che dovremo 563invocare \ml{RW\_TAC} in entrambi i rami dell'analisi dei casi. Questo pu� essere 564fatto usando \ml{THEN}. Quando $t_1 \ \mbox{\ml{THEN}}\ t_2$ � applicato 565a un goal $g$, prima $t_1$ � applicato a $g$, dando una lista di nuovi 566subgoal, poi $t_2$ � applicato ad ogni membro della lista. Tutti i goal 567risultanti da queste applicazioni di $t_2$ sono raccolti insieme e 568restituiti. 569\begin{session} 570\begin{verbatim} 571- e (Cases_on `x` THEN RW_TAC arith_ss [MULT_CLAUSES]); 572OK.. 573 574Goal proved. 575|- m <= m * x \/ (m * x = 0) 576> val it = 577 Initial goal proved. 578 |- !m n. m divides n ==> m <= n \/ (n = 0) 579\end{verbatim} 580\end{session} 581Questo � stato facile! Ovviamente fare un case split su $x$ era la scelta 582giusta. Il processo di {\it trovare\/} la dimostrazione ora � terminato, e 583tutto ci� che rimane da fare � impacchettare la dimostrazione in una singola 584tattica come abbiamo visto di sopra. Al posto di usare \ml{top\_thm} e il goalstack, 585possiamo bypassarlo e usare la funzione \ml{store\_thm}. Questa funzione 586prende una stringa, un termine e una tattica e applica la tattica al termine 587per ottenere un teorema, e quindi archivia il teorema nella teoria corrente 588sotto il nome dato. 589\begin{session} 590\begin{verbatim} 591- val DIVIDES_LE = store_thm ( 592 "DIVIDES_LE", 593 ``!m n. m divides n ==> m <= n \/ (n = 0)``, 594 RW_TAC arith_ss [divides_def] 595 THEN Cases_on `x` 596 THEN RW_TAC arith_ss [MULT_CLAUSES]); 597 598> val DIVIDES_LE = |- !m n. m divides n ==> m <= n \/ (n = 0) : thm 599\end{verbatim} 600\end{session} 601Archiviare i teoremi nel nostro script di salvataggio della sessione in questo stile 602(piuttosto che con il goalstack) risulta in uno script pi� conciso, e 603rende anche pi� facile trasformare il nostro script in un file di teoria, come facciamo 604nella sessione~\ref{sec:script-to-theory}. 605 606\subsection{Divisibilit� e fattoriale} 607 608Il prossimo lemma, {\small{\it DIVIDES\_FACT\/}}, dice che ogni numero 609maggiore di $0$ e $\leq n$ divide il fattoriale di 610$n$. Il fattoriale si trova in \verb+arithmeticTheory.FACT+ ed � stato 611definito per ricorsione primitiva: 612\begin{description} 613\item [\small{({\it FACT\/})}] 614\begin{minipage}[t]{0.5\textwidth} 615\begin{verbatim} 616 (FACT 0 = 1) /\ 617 (!n. FACT (SUC n) = SUC n * FACT n) 618\end{verbatim} 619\end{minipage} 620\end{description} 621Una dimostrazione lucidata di {\small{\it DIVIDES\_FACT\/}} � la 622seguente\footnote{Questa e le successive dimostrazioni usano i teoremi dimostrati 623 alla pagina~\pageref{euclid:extra-proofs}, che sono state aggiunte all'ambiente \ML{} 624 dopo essere state dimostrate.}: 625\begin{description} 626\item [\small{({\it DIVIDES\_FACT\/})}] 627\begin{tabular}[t]{l} 628\verb+!m n. 0 < m /\ m <= n ==> m divides (FACT n)+ \\ \hline 629\verb+RW_TAC arith_ss [LESS_EQ_EXISTS]+ \\ 630\verb+ THEN Induct_on `p`+ \\ 631\verb+ THEN RW_TAC arith_ss [FACT,ADD_CLAUSES]+ \\ 632\verb+ THENL [Cases_on `m`, ALL_TAC]+ \\ 633\verb+ THEN METIS_TAC [FACT, DECIDE ``!x. ~(x < x)``,+ \\ 634\verb+ DIVIDES_RMUL, DIVIDES_LMUL, DIVIDES_REFL]+ \\ 635\end{tabular} 636\end{description} 637Esamineremo questa dimostrazione nel dettaglio, cos� dovremmo prima tentare di 638comprendere perch� il teorema � vero. Qual � l'intuizione sottostante? 639Supponiamo che $0 < m \leq n$, e cos� $\mbox{\tt FACT}\ n = 1 * \cdots * m * 640\cdots * n$. Mostrare che $m\ \mbox{\tt divides}\ (\mbox{\tt FACT}\ n)$ 641significa esibire un $q$ tale che $q * m = \mbox{\tt FACT}\ n$. Cos� $q 642= \mbox{\tt FACT}\ n \div m$. Se dovessimo intraprendere questo approccio alla 643dimostrazione, finiremmo per dover trovare e applicare dei lemmi circa $\div$. 644Questo sembra portarci un p� fuori strada; non c'� una dimostrazione 645che non usa la divisione? Ebbene s�, possiamo dimostrare il teorema per 646induzione su $n - m$: nel caso migliore, dovremo dimostrare $n\; 647\mbox{\tt divides}\ (\mbox{\tt FACT}\; n)$, che dovrebbe essere facile; nel 648caso induttivo, l'ipotesi d'induzione sembrerebbe doverci dare 649ci� di cui abbiamo bisogno. Questa strategia per il caso induttivo � un p� vaga, 650perch� stiamo provando a figurarci mentalmente una formula piuttosto 651complicata, ma possiamo contare sul fatto che il sistema calcoli in modo accurato il 652i casi d'induzione per noi. Se il caso induttivo si riveler� non essere 653ci� che ci aspettavamo, dovremo ripensare il nostro approccio. 654\begin{session} 655\begin{verbatim} 656- g `!m n. 0 < m /\ m <= n ==> m divides (FACT n)`; 657 658> val it = 659 Proof manager status: 1 proof. 660 1. Incomplete: 661 Initial goal: 662 !m n. 0 < m /\ m <= n ==> m divides FACT n 663\end{verbatim} 664\end{session} 665Al posto di eseguire un'induzione direttamente su $n-m$, faremo un'induzione su una variabile 666testimone, ottenuta usando il teorema \verb+LESS_EQ_EXISTS+. 667\begin{session} 668\begin{verbatim} 669- LESS_EQ_EXISTS; 670> val it = |- !m n. m <= n = (?p. n = m + p) : thm 671 672- e (RW_TAC arith_ss [LESS_EQ_EXISTS]); 673OK.. 6741 subgoal: 675> val it = 676 m divides FACT (m + p) 677 ------------------------------------ 678 0 < m 679\end{verbatim} 680\end{session} 681\noindent Ora eseguiamo un'induzione su $p$: 682\begin{session} 683\begin{verbatim} 684- e (Induct_on `p`); 685OK.. 6862 subgoals: 687> val it = 688 m divides FACT (m + SUC p) 689 ------------------------------------ 690 0. 0 < m 691 1. m divides FACT (m + p) 692 693 m divides FACT (m + 0) 694 ------------------------------------ 695 0 < m 696\end{verbatim} 697\end{session} 698\noindent Il primo goal pu� ovviamente essere semplificato: 699\begin{session} 700\begin{verbatim} 701- e (RW_TAC arith_ss []); 702OK.. 7031 subgoal: 704> val it = 705 m divides FACT m 706 ------------------------------------ 707 0 < m 708\end{verbatim} 709\end{session} 710\noindent Ora possiamo fare un'analisi dei casi su $m$: se � $0$, abbiamo un 711goal banale; se � un successore, allora possiamo usare la definizione di 712\ml{FACT} e i teoremi \ml{DIVIDES\_RMUL} e 713\ml{DIVIDES\_REFL}. 714\begin{session} 715\begin{verbatim} 716- e (Cases_on `m`); 717OK.. 7182 subgoals: 719> val it = 720 SUC n divides FACT (SUC n) 721 ------------------------------------ 722 0 < SUC n 723 724 0 divides FACT 0 725 ------------------------------------ 726 0 < 0 727\end{verbatim} 728\end{session} 729 730 Qui il primo subgoal ha un'assunzione che � falsa, Possiamo 731 dimostrare questo al sistema usando la funzione 732\ml{DECIDE} per dimostrare un semplice fatto dell'aritmetica (cio�, che nessun 733numero $x$ � minore di s� stesso), e quindi passare il teorema 734risultante a \ml{METIS\_TAC}, che pu� combinare questo con l'assunzione 735contraddittoria\footnote{Si noti come il sistema interattivo 736 stampi il teorema dimostrato con \ml{[.]} prima del 737 turnstile. Questa notazione indica che un teorema ha un'assunzione 738(in questo caso l'asserzione falsa $0<0$).}. 739 740\begin{session} 741\begin{verbatim} 742- e (METIS_TAC [DECIDE ``!x. ~(x < x)``]); 743OK.. 744metis: r[+0+4]# 745 746Goal proved. 747 [.] |- 0 divides FACT 0 748 749Remaining subgoals: 750> val it = 751 SUC n divides FACT (SUC n) 752 ------------------------------------ 753 0 < SUC n 754\end{verbatim} 755\end{session} 756Usando i teoremi identificati di sopra, il subgoal rimanente pu� 757essere dimostrato con \ml{RW\_TAC}. 758 759\begin{session} 760\begin{verbatim} 761- e (RW_TAC arith_ss [FACT, DIVIDES_LMUL, DIVIDES_REFL]); 762OK.. 763 764Goal proved. ... 765 766Remaining subgoals: 767> val it = 768 m divides FACT (m + SUC p) 769 ------------------------------------ 770 0. 0 < m 771 1. m divides FACT (m + p) 772\end{verbatim} 773\end{session} 774Quest'ultimo passo, cio� l'invocazione di \ml{RW\_TAC}, 775potrebbe essere ottenuta anche con \ml{METIS\_TAC}. Si noti che 776l'unica differenza � l'uso di \ml{DIVIDES\_LMUL} nel semplificatore 777\emph{al posto di} \ml{DIVIDES\_RMUL} in \ml{METIS\_TAC}. Questo � dovuto al 778gi� menzionato riarrangiamento algebrico dei termini aritmetici nel semplificatore. 779\begin{session} 780\begin{verbatim} 781- b(); 782> ... 783 784- e (METIS_TAC [FACT, DIVIDES_RMUL, DIVIDES_REFL]); 785OK.. 786 787Goal proved. ... 788\end{verbatim} 789\end{session} 790Ora abbiamo completato il caso base dell'induzione e possiamo spostarci al 791caso di passo. Una cosa ovvia da provare � la semplificazione con le 792definizioni dell'addizione e del fattoriale: 793\begin{session} 794\begin{verbatim} 795- e (RW_TAC arith_ss [FACT, ADD_CLAUSES]); 796 797OK.. 7981 subgoal: 799> val it = 800 m divides FACT (m + p) * SUC (m + p) 801 ------------------------------------ 802 0. 0 < m 803 1. m divides FACT (m + p) 804\end{verbatim} 805\end{session} 806\noindent E ora, per mezzo di \ml{DIVIDES\_RMUL} e l'ipotesi d'induzione, abbiamo 807finito: 808\begin{session} 809\begin{verbatim} 810- e (METIS_TAC [DIVIDES_RMUL]); 811OK.. 812metis: r[+0+5]+0+0+0+0+1# 813 814Goal proved. 815 ... 816> val it = 817 Initial goal proved. 818 |- !m n. 0 < m /\ m <= n ==> m divides FACT n 819\end{verbatim} 820\end{session} 821Abbiamo concluso la ricerca della dimostrazione, e possiamo spostarci al compito di 822creare una singola tattica a partire dalla sequenza delle invocazioni delle tattiche che abbiamo 823appena fatto. Assumiamo che sia stata tenuta traccia della sequenza delle invocazioni 824in un file o nel buffer di un editor di testo. Avremmo dunque qualcosa 825di simile a ci� che segue: 826\begin{hol} 827\begin{verbatim} 828 e (RW_TAC arith_ss [LESS_EQ_EXISTS]); 829 e (Induct_on `p`); 830 (*1*) 831 e (RW_TAC arith_ss []); 832 e (Cases_on `m`); 833 (*1.1*) 834 e (METIS_TAC [DECIDE ``!x. ~(x < x)``]); 835 (*1.2*) 836 e (RW_TAC arith_ss [FACT, DIVIDES_LMUL, DIVIDES_REFL]); 837 (*2*) 838 e (RW_TAC arith_ss [FACT, ADD_CLAUSES]); 839 e (METIS_TAC [DIVIDES_RMUL]); 840\end{verbatim} 841\end{hol} 842\noindent 843 844Abbiamo aggiunto uno schema di numerazione per tenere traccia dei rami nella 845dimostrazione. Possiamo cucire insieme l'espressioni di sopra nella seguente tattica 846composta: 847 848\begin{hol} 849\begin{verbatim} 850 RW_TAC arith_ss [LESS_EQ_EXISTS] 851 THEN Induct_on `p` 852 THENL [RW_TAC arith_ss [] THEN Cases_on `m` 853 THENL [METIS_TAC [DECIDE ``!x. ~(x < x)``], 854 RW_TAC arith_ss [FACT, DIVIDES_LMUL, DIVIDES_REFL]], 855 RW_TAC arith_ss [FACT, ADD_CLAUSES] THEN METIS_TAC [DIVIDES_RMUL]] 856\end{verbatim} 857\end{hol} 858 859\noindent Questo pu� essere testato per vedere che non abbiamo fatto errori: 860 861\begin{session} 862\begin{verbatim} 863- restart(); 864> ... 865 866- e (RW_TAC arith_ss [LESS_EQ_EXISTS] 867 THEN Induct_on `p` THENL 868 [RW_TAC arith_ss [] THEN Cases_on `m` THENL 869 [METIS_TAC [DECIDE ``!x. ~(x < x)``], 870 RW_TAC arith_ss [FACT, DIVIDES_LMUL, DIVIDES_REFL]], 871 RW_TAC arith_ss [FACT, ADD_CLAUSES] THEN METIS_TAC [DIVIDES_RMUL]]); 872OK.. 873metis: r[+0+5]+0+0+0+0+1# 874metis: r[+0+4]# 875> val it = 876 Initial goal proved. 877 |- !m n. 0 < m /\ m <= n ==> m divides FACT n 878\end{verbatim} 879\end{session} 880 881Per molti utenti, questa sarebbe la conclusione di questa dimostrazione: la 882tattica ora pu� essere impacchettata in un'invocazione di 883\ml{prove}\footnote{La funzione \ml{prove} prende un termine e una tattica 884e tenta di dimostrare il termine usando la tattica fornita. Essa 885restituisce il teorema dimostrato se la tattica ha successo. Essa non salva 886il teorema alla teoria sviluppata.} o di \ml{store\_thm} e quella 887sarebbe la conclusione. Comunque, un altro utente potrebbe notare 888che questa tattica potrebbe essere abbreviata. 889 890Per iniziare, entrambi i rami dell'induzione iniziano con un'invocazione di 891\ml{RW\_TAC}, e la semantica di \ml{THEN} ci permette di fondere le 892occorrenze di \ml{RW\_TAC} prima di \ml{THENL}. La tattica rimaneggiata 893� 894\begin{hol} 895\begin{verbatim} 896 RW_TAC arith_ss [LESS_EQ_EXISTS] 897 THEN Induct_on `p` 898 THEN RW_TAC arith_ss [FACT, ADD_CLAUSES] 899 THENL [Cases_on `m` THENL 900 [METIS_TAC [DECIDE ``!x. ~(x < x)``], 901 RW_TAC arith_ss [FACT, DIVIDES_LMUL, DIVIDES_REFL]], 902 METIS_TAC [DIVIDES_RMUL]] 903\end{verbatim} 904\end{hol} 905(Naturalmente, quando una tattica � stata rivisitata, dovrebbe essere testata per vedere 906se continua a dimostrare il goal!) Ora si ricordi che l'uso di \ml{RW\_TAC} 907nel caso base potrebbe essere sostituito da una chiamata a \ml{METIS\_TAC}. Cos� 908sembra possibile fondere i due sotto casi del caso base in un'unica 909invocazione di \ml{METIS\_TAC}: 910 911\begin{hol} 912\begin{verbatim} 913 RW_TAC arith_ss [LESS_EQ_EXISTS] 914 THEN Induct_on `p` 915 THEN RW_TAC arith_ss [FACT, ADD_CLAUSES] 916 THENL [Cases_on `m` THEN 917 METIS_TAC[DECIDE ``!x. ~(x<x)``,FACT,DIVIDES_RMUL,DIVIDES_REFL], 918 METIS_TAC [DIVIDES_RMUL]] 919\end{verbatim} 920\end{hol} 921 922\noindent 923In fine, spingendo questo revisionismo quasi al suo limite, ci 924piacerebbe che ci fosse un'unica invocazione di \ml{METIS\_TAC} per concludere 925la dimostrazione. La semantica di \ml{THEN} e di \ml{ALL\_TAC} vengono 926in nostro aiuto: divideremo la costruzione di $m$ nel caso base, 927come nell'incarnazione attuale della tattica, ma lasceremo il 928caso induttivo di passo inalterato attraverso \ml{THENL}. Questo si ottiene 929usando \verb+ALL_TAC+, questa � una tattica che agisce come una funzione 930d'identit� sul goal. 931\begin{hol} 932\begin{verbatim} 933 RW_TAC arith_ss [LESS_EQ_EXISTS] 934 THEN Induct_on `p` 935 THEN RW_TAC arith_ss [FACT, ADD_CLAUSES] 936 THENL [Cases_on `m`, ALL_TAC] 937 THEN METIS_TAC [DECIDE ``!x. ~(x < x)``, 938 FACT, DIVIDES_RMUL, DIVIDES_REFL] 939\end{verbatim} 940\end{hol} 941 942\noindent 943Il risultato � che ci saranno tre subgoal risultanti da 944\ml{THENL}: i due sotto casi nel caso base e il caso di passo 945inalterato. Ciascuno � dimostrato con una chiamata a \ml{METIS\_TAC}. Abbiamo finito ora? 946Non necessariamente. Per esempio, il case split esplicito, cio� \ml{Cases\_on `m`}, 947pu� essere sostituito fornendo il teorema dei \emph{casi} per i numeri naturali 948(\ml{num\_CASES}) a \ml{METIS\_TAC}. Con questo, il case split su $m$, sar� 949generato automaticamente da \ml{METIS\_TAC} durante la ricerca della dimostrazione. Di conseguenza 950possiamo abbreviare la tattica di nuovo. 951\begin{session} 952\begin{verbatim} 953- num_CASES; 954> val it = |- !m. (m = 0) \/ ?n. m = SUC n : thm 955 956- restart(); 957- e (RW_TAC arith_ss [LESS_EQ_EXISTS] 958 THEN Induct_on `p` 959 THEN METIS_TAC [DECIDE ``!x. ~(x < x)``, FACT, num_CASES, 960 DIVIDES_RMUL, DIVIDES_LMUL, DIVIDES_REFL, ADD_CLAUSES]); 961\end{verbatim} 962\end{session} 963Ora abbiamo concluso il nostro esercizio di revisione delle tattiche. Certamente, 964sarebbe difficile indovinare che questa tattica finale dimostrerebbe il 965goal; i lemmi richiesti per l'invocazione finale di \ml{METIS\_TAC} 966sono stati trovati attraverso un processo incrementale di revisione. 967 968\subsection{Divisibilit� e fattoriale (di nuovo!)} 969 970Nella precedente dimostrazione, abbiamo fatto un passo di semplificazione iniziale al fine 971di esporre una variabile su cui indurre. Comunque, la dimostrazione in realt� 972� su $n - m$. Possiamo esprimere questo in modo diretto? La 973risposta � un s� con riserva: l'induzione pu� essere dichiarata in modo naturale, ma 974porta a dei goal in qualche modo meno naturali. 975\begin{session} 976\begin{verbatim} 977- restart(); 978 979- e (Induct_on `n - m`); 980 981OK.. 9822 subgoals: 983> val it = 984 !n m. (SUC v = n - m) ==> 0 < m /\ m <= n ==> m divides FACT n 985 ------------------------------------ 986 !n m. (v = n - m) ==> 0 < m /\ m <= n ==> m divides FACT n 987 988 !n m. (0 = n - m) ==> 0 < m /\ m <= n ==> m divides FACT n 989\end{verbatim} 990\end{session} 991 Questo � leggermente complicato da leggere, cos� usiamo \ml{STRIP\_TAC} e 992 \ml{REPEAT} per spostare gli antecedenti dei goal nelle 993 assunzioni. L'uso di \ml{THEN} assicura che la tatticca venga applicata 994 in entrambi i rami dell'induzione. 995\begin{session} 996\begin{verbatim} 997- b(); 998 ... 999 1000- e (Induct_on `n - m` THEN REPEAT STRIP_TAC); 1001 1002OK.. 10032 subgoals: 1004> val it = 1005 m divides FACT n 1006 ------------------------------------ 1007 0. !n m. (v = n - m) ==> 0 < m /\ m <= n ==> m divides FACT n 1008 1. SUC v = n - m 1009 2. 0 < m 1010 3. m <= n 1011 1012 m divides FACT n 1013 ------------------------------------ 1014 0. 0 = n - m 1015 1. 0 < m 1016 2. m <= n 1017\end{verbatim} 1018\end{session} 1019Osservando il primo goal, ragioniamo che se $0 = n - m$ e $m 1020\leq n$, allora $m = n$. Possiamo dimostrare questo fatto, usando \ml{DECIDE\_TAC}\footnote 1021{\ml{DECIDE\_TAC} � una procedura di decisione per un'utile classe di formule aritmetiche.} 1022e aggiungerla alle ipotesi per mezzo dell'uso dell'operatore infisso ``\ml{by}'': 1023\begin{session} 1024\begin{verbatim} 1025- e (`m = n` by DECIDE_TAC); 1026OK.. 10271 subgoal: 1028> val it = 1029 m divides FACT n 1030 ------------------------------------ 1031 0. 0 = n - m 1032 1. 0 < m 1033 2. m <= n 1034 3. m = n 1035\end{verbatim} 1036\end{session} 1037 1038\noindent Ora possiamo usare \ml{RW\_TAC} per propagare l'uguaglianza appena derivata 1039attraverso il goal. 1040\begin{session} 1041\begin{verbatim} 1042- e (RW_TAC arith_ss []); 1043 1044OK.. 10451 subgoal: 1046> val it = 1047 m divides FACT m 1048 ------------------------------------ 1049 0. 0 = m - m 1050 1. 0 < m 1051 2. m <= m 1052\end{verbatim} 1053\end{session} 1054 A questo punto nella dimostrazione precedente abbiamo fatto un'analisi dei casi su $m$. 1055 Comunque, abbiamo gi� l'ipotesi che $m$ � positivo 1056 (insieme alle altre due ipotesi al momento inutili). Cos� sappiamo che 1057 $m$ � il successore di qualche numero $k$. Potremmo desiderare di affermare 1058 questo fatto con un'invocazione di ``\ml{by}'' nel modo seguente: 1059\[ 1060 \mbox{\ml{`?k. m = SUC k` by <tactic>}} 1061\] 1062Ma qual � la tattica? Se proviamo \ml{DECIDE\_TAC}, essa fallir� dal momento che 1063non gestisce enunciati esistenziali. Anche un'applicazione di 1064\ml{RW\_TAC} si dimostrer� insoddisfacente. Cosa fare? 1065 1066Quando capita una situazione di questo tipo, � spesso meglio iniziare una nuova dimostrazione per il 1067lemma richiesto. Questo si pu� fare semplicemente invocando ``\ml{g}'' 1068di nuovo. Un nuovo goalstack sar� creato e aggiunto a quello 1069corrente\footnote{Questa aggiunta di tentativi di dimostrazione (goalstack) � differente 1070 dall'aggiunta di goal e giustificazioni all'interno di un particolare 1071 goalstack.} e sar� stampata una panoramica dei tentativi di dimostrazione 1072esistenti: 1073\begin{session} 1074\begin{verbatim} 1075- g `!m. 0 < m ==> ?k. m = SUC k`; 1076 1077> val it = 1078 Proof manager status: 2 proofs. 1079 2. Incomplete: 1080 Initial goal: 1081 !m n. 0 < m /\ m <= n ==> m divides FACT n 1082 1083 1084 Current goal: 1085 m divides FACT m 1086 ------------------------------------ 1087 0. 0 = m - m 1088 1. 0 < m 1089 2. m <= m 1090 1091 1. Incomplete: 1092 Initial goal: 1093 !m. 0 < m ==> ?k. m = SUC k 1094\end{verbatim} 1095\end{session} 1096 Il nostro nuovo goal pu� essere dimostrato abbastanza velocemente. Una volta che lo abbiamo dimostrato, 1097 possiamo legarlo a un nome ML e usarlo nella dimostrazione precedente, per 1098 mezzo di una specie di gioco di prestigio con la funzione ``\ml{before}''\footnote{Una 1099 versione infissa del combinatore {\tt K}, definito da {\tt fun (x before 1100 y) = x}.} 1101\begin{session} 1102\begin{verbatim} 1103- e (Cases THEN RW_TAC arith_ss []); 1104 1105OK.. 1106> val it = 1107 Initial goal proved. 1108 |- !m. 0 < m ==> ?k. m = SUC k 1109 1110- val lem = top_thm() before drop(); 1111 1112OK.. 1113> val lem = |- !m. 0 < m ==> ?k. m = SUC k : thm 1114\end{verbatim} 1115\end{session} 1116 1117Ora possiamo ritornare al filo principale della dimostrazione. Lo stato del 1118subgoal corrente della dimostrazione pu� essere mostrato usando la funzione 1119``\ml{p}''. 1120 1121\begin{session} 1122\begin{verbatim} 1123- p (); 1124 1125> val it = 1126 m divides FACT m 1127 ------------------------------------ 1128 0. 0 = m - m 1129 1. 0 < m 1130 2. m <= m 1131\end{verbatim} 1132\end{session} 1133 Ora possiamo usare \ml{lem} nella dimostrazione. Un p� opportunisticamente, 1134 vireremo sull'invocazione usata nella precedente dimostrazione (pi� o meno) 1135 allo stesso punto, sperando che questo risolva il goal: 1136\begin{session} 1137\begin{verbatim} 1138- e (`?k. m = SUC k` by 1139 METIS_TAC[lem] THEN RW_TAC arith_ss [FACT, DIVIDES_LMUL, DIVIDES_REFL]); 1140OK.. 1141metis: r[+0+6]+0+0+0+0+0+1# 1142 1143Goal proved. ... 1144 1145Remaining subgoals: 1146> val it = 1147 m divides FACT n 1148 ------------------------------------ 1149 0. !n m. (v = n - m) ==> 0 < m /\ m <= n ==> m divides FACT n 1150 1. SUC v = n - m 1151 2. 0 < m 1152 3. m <= n 1153\end{verbatim} 1154\end{session} 1155 Funziona! Questo si occupa del caso base, Per il passo d'induzione, 1156 le cose sembrano un p� pi� complicate che nella dimostrazione precedente. 1157 Comunque, possiamo fare progressi realizzando che l'ipotesi 1158 implica che $0 < n$ e cos�, di nuovo per mezzo di \ml{lem}, possiamo trasformare $n$ 1159 in un successore, abilitando di conseguenza l'espansione di \ml{FACT}, come nella 1160 dimostrazione precedente: 1161\begin{session} 1162\begin{verbatim} 1163- e (`0 < n` by DECIDE_TAC THEN `?k. n = SUC k` by METIS_TAC [lem]); 1164OK.. 1165metis: r[+0+8]+0+0+0+0+0+0+2# 11661 subgoal: 1167> val it = 1168 m divides FACT n 1169 ------------------------------------ 1170 0. !n m. (v = n - m) ==> 0 < m /\ m <= n ==> m divides FACT n 1171 1. SUC v = n - m 1172 2. 0 < m 1173 3. m <= n 1174 4. 0 < n 1175 5. n = SUC k 1176\end{verbatim} 1177\end{session} 1178\noindent La dimostrazione ora si conclude nello stesso modo di quella precedente: 1179\begin{session} 1180\begin{verbatim} 1181- e (RW_TAC arith_ss [FACT, DIVIDES_RMUL]); 1182OK.. 1183 1184Goal proved. ... 1185> val it = 1186 Initial goal proved. 1187 |- !m n. 0 < m /\ m <= n ==> m divides FACT n 1188\end{verbatim} 1189\end{session} 1190\noindent Lasciamo i dettagli del cucire insieme la dimostrazione al lettore 1191interessato. 1192 1193\section{Primariet�} 1194 1195Ora ci spostiamo a stabilire alcuni fatti circa la primariet� dei 1196primi numeri: $0$ e $1$ non sono primi, ma $2$ lo �. Inoltre, tutti 1197i primi sono positivi. Queste sono piuttosto semplici da dimostrare. 1198 1199\begin{description} 1200 1201\item [\small{({\it NOT\_PRIME\_0\/})}] 1202\begin{tabular}[t]{l} 1203\verb+~prime 0+ \\ \hline 1204\verb+RW_TAC arith_ss [prime_def,DIVIDES_0]+ \\ 1205\end{tabular} 1206 1207\item [\small{({\it NOT\_PRIME\_1\/})}] 1208\begin{tabular}[t]{l} 1209\verb+~prime 1+ \\ \hline 1210\verb+RW_TAC arith_ss [prime_def]+ \\ 1211\end{tabular} 1212 1213\item [\small{({\it PRIME\_2\/})}] 1214\begin{tabular}[t]{l} 1215\verb+prime 2+ \\ \hline 1216\verb+RW_TAC arith_ss [prime_def]+ \\ 1217\verb+ THEN METIS_TAC [DIVIDES_LE, DIVIDES_ZERO,+ \\ 1218\verb+ DECIDE ``~(2=1)``, DECIDE ``~(2=0)``,+ \\ 1219\verb+ DECIDE ``x <= 2 = (x=0) \/ (x=1) \/ (x=2)``]+ \\ 1220\end{tabular} 1221 1222\item [\small{({\it PRIME\_POS\/})}] 1223\begin{tabular}[t]{l} 1224\verb+!p. prime p ==> 0<p+ \\ \hline 1225\verb+Cases THEN RW_TAC arith_ss [NOT_PRIME_0]+ \\ 1226\end{tabular} 1227\end{description} 1228 1229\section{Esistenza dei fattori primi} 1230 1231Ora siamo nella posizione di dimostrare un lemma pi� sostanziale: ogni numero 1232diverso da $1$ ha un fattore primo. La dimostrazione procede attraverso 1233un'\emph{induzione completa} su $n$. L'induzione completa � 1234necessaria dal momento che un fattore primo non sar� un predecessore. Dopo 1235l'induzione, la dimostrazione si divide nei casi se $n$ � primo o 1236no. Il primo caso ($n$ � primo) � 1237banale. Nel secondo caso, ci deve essere un $x$ che divide $n$, e 1238$x$ non � $1$ o $n$. Per {\small\it DIVIDES\_LE}, $n=0$ o $x \leq n$. Se 1239$n=0$, allora $2$ � un primo che divide $0$. Dall'altro lato, se $x \leq 1240n$, ci sono due casi: se $x < n$ allora possiamo usare l'ipotesi 1241d'induzione e per la transitivit� di \ml{divides} abbiamo finito; altrimenti, 1242$x=n$ e quindi abbiamo una contraddizione con il fatto che $x$ non � $1$ 1243n� $n$. La tattica ripulita � la seguente: 1244\begin{description} 1245\item [\small{({\it PRIME\_FACTOR\/})}] 1246\begin{tabular}[t]{l} 1247\verb+!n. ~(n = 1) ==> ?p. prime p /\ p divides n+ \\ \hline 1248\verb+completeInduct_on `n`+ \\ 1249\verb+ THEN RW_TAC arith_ss []+ \\ 1250\verb+ THEN Cases `prime n` THENL+ \\ 1251\verb+ [METIS_TAC [DIVIDES_REFL], + \\ 1252\verb+ `?x. x divides n /\ ~(x=1) /\ ~(x=n)` + \\ 1253\verb+ by METIS_TAC[prime_def]+ \\ 1254\verb+ THEN METIS_TAC [LESS_OR_EQ, PRIME_2, +\\ 1255\verb+ DIVIDES_LE,DIVIDES_TRANS,DIVIDES_0]]+ \\ 1256\end{tabular} 1257\end{description} 1258Iniziamo invocando l'induzione completa. Questo ci d� un'ipotesi 1259d'induzione che vale per ogni numero $m$ strettamente minore di $n$: 1260\begin{session} 1261\begin{verbatim} 1262- g `!n. ~(n = 1) ==> ?p. prime p /\ p divides n`; 1263 1264- e (completeInduct_on `n`); 1265OK.. 12661 subgoal: 1267> val it = 1268 ~(n = 1) ==> ?p. prime p /\ p divides n 1269 ------------------------------------ 1270 !m. m < n ==> ~(m = 1) ==> ?p. prime p /\ p divides m 1271\end{verbatim} 1272\end{session} 1273Possiamo spostare l'antecedente nelle ipotesi e fare il nostro case 1274split. Si noti che il termine dato a \ml{Cases\_on} non deve per forza essere nel 1275goal: 1276\begin{session} 1277\begin{verbatim} 1278- e (RW_TAC arith_ss [] THEN Cases_on `prime n`); 1279OK.. 12802 subgoals: 1281> val it = 1282 ?p. prime p /\ p divides n 1283 ------------------------------------ 1284 0. !m. m < n ==> ~(m = 1) ==> ?p. prime p /\ p divides m 1285 1. ~(n = 1) 1286 2. ~prime n 1287 1288 ?p. prime p /\ p divides n 1289 ------------------------------------ 1290 0. !m. m < n ==> ~(m = 1) ==> ?p. prime p /\ p divides m 1291 1. ~(n = 1) 1292 2. prime n 1293\end{verbatim} 1294\end{session} 1295\noindent Come menzionato, il primo caso � dimostrato con la riflessivit� della 1296divisibilit�: 1297\begin{session} 1298\begin{verbatim} 1299- e (METIS_TAC [DIVIDES_REFL]); 1300OK.. 1301metis: r[+0+7]+0+0+0+0+1# 1302 1303Goal proved. ... 1304\end{verbatim} 1305\end{session} 1306\noindent 1307Nel secondo caso, otteniamo un divisore di $n$ che non � $1$ n� $n$ 1308(dal momento che $n$ non � primo): 1309\begin{session} 1310\begin{verbatim} 1311- e (`?x. x divides n /\ ~(x=1) /\ ~(x=n)` by METIS_TAC [prime_def]); 1312OK.. 1313metis: r[+0+11]+0+0+0+0+0+0+1+1+1+1+0+1+1# 13141 subgoal: 1315> val it = 1316 ?p. prime p /\ p divides n 1317 ------------------------------------ 1318 0. !m. m < n ==> ~(m = 1) ==> ?p. prime p /\ p divides m 1319 1. ~(n = 1) 1320 2. ~prime n 1321 3. x divides n 1322 4. ~(x = 1) 1323 5. ~(x = n) 1324\end{verbatim} 1325\end{session} 1326A questo punto, la tattica ripulita invoca semplicemente \ml{METIS\_TAC} con 1327una collezione di teoremi. Tenteremo un'esposizione pi� 1328dettagliata. Data l'ipotesi, e {\small\it DIVIDES\_LE}, possiamo 1329affermare $x < n \lor n = 0$ e cos� dividere la dimostrazione in due casi: 1330\begin{session} 1331\begin{verbatim} 1332- e (`x < n \/ (n=0)` by METIS_TAC [DIVIDES_LE,LESS_OR_EQ]); 1333OK.. 1334metis: r[+0+14]+0+0+0+0+0+0+0+0+0+0+1+0+1# 13352 subgoals: 1336> val it = 1337 ?p. prime p /\ p divides n 1338 ------------------------------------ 1339 0. !m. m < n ==> ~(m = 1) ==> ?p. prime p /\ p divides m 1340 1. ~(n = 1) 1341 2. ~prime n 1342 3. x divides n 1343 4. ~(x = 1) 1344 5. ~(x = n) 1345 6. n = 0 1346 1347 ?p. prime p /\ p divides n 1348 ------------------------------------ 1349 0. !m. m < n ==> ~(m = 1) ==> ?p. prime p /\ p divides m 1350 1. ~(n = 1) 1351 2. ~prime n 1352 3. x divides n 1353 4. ~(x = 1) 1354 5. ~(x = n) 1355 6. x < n 1356\end{verbatim} 1357\end{session} 1358Nel primo subgoal, possiamo vedere che gli antecedenti dell'ipotesi 1359d'induzione sono soddisfatti e cos� $x$ ha un divisore primo. Possiamo quindi usare 1360la transitivit� della divisibilit� per ottenere il fatto che questo divisore di $x$ � 1361anche un divisore di $n$, concludendo quindi questo ramo della dimostrazione: 1362\begin{session} 1363\begin{verbatim} 1364- e (METIS_TAC [DIVIDES_TRANS]); 1365OK.. 1366metis: r[+0+11]+0+0+0+0+0+0+0+1+0+4+1+0+3+0+2+2+1# 1367 1368Goal proved. 1369\end{verbatim} 1370\end{session} 1371\noindent I goal rimanenti possono essere chiariti per semplificazione: 1372\begin{session} 1373\begin{verbatim} 1374- e (RW_TAC arith_ss []); 1375OK.. 13761 subgoal: 1377> val it = 1378 ?p. prime p /\ p divides 0 1379 ------------------------------------ 1380 0. !m. m < 0 ==> ~(m = 1) ==> ?p. prime p /\ p divides m 1381 1. ~(0 = 1) 1382 2. ~prime 0 1383 3. x divides 0 1384 4. ~(x = 1) 1385 5. ~(x = 0) 1386 1387- DIVIDES_0; 1388> val it = |- !x. x divides 0 : thm 1389 1390- e (RW_TAC arith_ss [it]); 1391OK.. 13921 subgoal: 1393> val it = 1394 ?p. prime p 1395 ------------------------------------ 1396 0. !m. m < 0 ==> ~(m = 1) ==> ?p. prime p /\ p divides m 1397 1. ~(0 = 1) 1398 2. ~prime 0 1399 3. x divides 0 1400 4. ~(x = 1) 1401 5. ~(x = 0) 1402\end{verbatim} 1403\end{session} 1404I due passi della semplificazione esplorativa ci hanno portato a uno stato dove 1405tutto ci� che dobbiamo fare � esibire un primo. E ne abbiamo gi� uno a portata di mano: 1406\begin{session} 1407\begin{verbatim} 1408- e (METIS_TAC [PRIME_2]); 1409OK.. 1410metis: r[+0+6]# 1411 1412Goal proved. ... 1413> val it = 1414 Initial goal proved. 1415 |- !n. ~(n = 1) ==> ?p. prime p /\ p divides n 1416\end{verbatim} 1417\end{session} 1418Di nuovo, � necessario fare del lavoro per comporre e magari ripulire una singola 1419tattica, dai passi individuali di dimostrazione, ma non lo descriveremo\footnote{ 1420Di fatto, la tattica pu� essere semplificata in un'induzione completa 1421 seguita da un'invocazione di \ml{METIS\_TAC} con lemmi adeguati.}. 1422Piuttosto andiamo avanti, perch� il nostro obiettivo finale � a portata di mano. 1423 1424\section{Il teorema di Euclide} 1425 1426\noindent{\bf Teorema.} Ogni numero ha un primo pi� grande di lui.\\ 1427\noindent {\it Dimostrazione Informale.} \\ 1428\noindent Assumiamo l'opposto; allora c'� un $n$ 1429tale che tutti i $p$ pi� grandi di $n$ non sono primi. Si consideri $\mbox{\tt 1430FACT}(n) + 1$: esso non � uguale a 1 cos�, per {\small{\it PRIME\_FACTOR}}, 1431c'� un primo $p$ che lo divide. Si noti che $p$ divide anche 1432$\mbox{\tt FACT}(n)$ perch� $p \leq n$\footnote{Per {\small{\it DIVIDES\_FACT}} [ndt].}. Per {\small{\it DIVIDES\_ADDL}}, 1433abbiamo $p=1$. Ma allora $p$ non � primo, il che � una contraddizione. \\ 1434\noindent {\it Fine della dimostrazione}. 1435 1436Una traduzione in HOL della dimostrazione pu� essere data nel modo seguente: 1437\begin{description} 1438\item [\small{({\it EUCLID\/})}] 1439\begin{tabular}[t]{l} 1440\verb+!n. ?p. n < p /\ prime p+ \\ \hline 1441\verb+SPOSE_NOT_THEN STRIP_ASSUME_TAC+ \\ 1442\verb! THEN MP_TAC (SPEC ``FACT n + 1`` PRIME_FACTOR)! \\ 1443\verb+ THEN RW_TAC arith_ss [FACT_LESS, DECIDE ``~(x=0) = 0<x``]+ \\ 1444\verb+ THEN METIS_TAC [NOT_PRIME_1, NOT_LESS, PRIME_POS, + \\ 1445\verb+ DIVIDES_FACT, DIVIDES_ADDL, DIVIDES_ONE]+ \\ 1446\end{tabular} 1447\end{description} 1448Consideriamo questo a parte e osserviamolo nel dettaglio. Una dimostrazione per 1449contraddizione pu� essere avviata usando la funzione di \ml{bossLib} 1450\ml{SPOSE\_NOT\_THEN}. Con essa, si assume la negazione del 1451goal attuale e quindi la si usa nel tentativo di dimostrare la falsit� 1452(\verb+F+). La negazione assunta $\neg(\forall n.\ \exists p.\ n < p 1453\land \mbox{\tt prime}\ p)$ � semplificata un p� in $\exists n.\ 1454\forall p.\ n < p \supset \, \neg \,\mbox{\tt prime}\ p$ e poi � 1455passata alla tattica \ml{STRIP\_ASSUME\_TAC}. Questo sposta il suo argomento 1456alla lista delle assunzioni del goal dopo aver eliminato la quantificazione 1457esistenziale su $n$. 1458\begin{session} 1459\begin{verbatim} 1460- g `!n. ?p. n < p /\ prime p`; 1461 1462- e (SPOSE_NOT_THEN STRIP_ASSUME_TAC); 1463OK.. 14641 subgoal: 1465> val it = 1466 F 1467 ------------------------------------ 1468 !p. n < p ==> ~prime p 1469\end{verbatim} 1470\end{session} 1471Cos� abbiamo l'ipotesi che tutti i $p$ al di sopra di un certo $n$ non 1472specificato non sono primi, e il nostro compito � di mostrare che ci� non pu� essere. A questo 1473punto approfittiamo della grande ispirazione di Euclide e costruiamo un 1474termine esplicito da $n$. Nella dimostrazione informale ci viene chiesto di `considerare' 1475il termine $\mbox{\tt FACT}\ n + 1$\footnote{Il parser di HOL pensa che 1476$\mbox{\tt FACT}\ n + 1$ sia equivalente a $(\mbox{\tt FACT}\ n) + 1$.} 1477Questo termine avr� certe propriet� (cio�, ha un fattore primo) che 1478porta a una contraddizione. Domanda: come `consideriamo' questo termine nella 1479dimostrazione formale HOL? Risposta: istanziando un lemma con esso e portando il 1480lemma nella dimostrazione. Il lemma e la sua istanziazione sono \footnote{La 1481funzione {\tt SPEC} implementa la regola della specializzazione universale.}: 1482\begin{session} 1483\begin{verbatim} 1484- PRIME_FACTOR; 1485> val it = |- !n. ~(n = 1) ==> (?p. prime p /\ p divides n) : thm 1486 1487- val th = SPEC ``FACT n + 1`` PRIME_FACTOR; 1488> val th = 1489 |- ~(FACT n + 1 = 1) ==> (?p. prime p /\ p divides FACT n + 1) 1490\end{verbatim} 1491\end{session} 1492E' evidente che l'antecedente di \ml{th} pu� essere eliminato. In 1493\holn{}, si potrebbe fare questo in un cosiddetto stile di dimostrazione {\it in avanti\/} (dimostrando 1494$\vdash \neg(\mbox{\tt FACT}\ n + 1 = 1)$ e poi applicando {\it 1495modus ponens}, il cui risultato pu� poi essere usato nella dimostrazione), oppure 1496si potrebbe portare \ml{th} nella dimostrazione e semplificarlo {\it in 1497situ}. Scegliamo il secondo approccio. 1498\begin{session} 1499\begin{verbatim} 1500- e (MP_TAC (SPEC ``FACT n + 1`` PRIME_FACTOR)); 1501OK.. 15021 subgoal: 1503> val it = 1504 (~(FACT n + 1 = 1) ==> ?p. prime p /\ p divides FACT n + 1) ==> F 1505 ------------------------------------ 1506 !p. n < p ==> ~prime p 1507\end{verbatim} 1508\end{session} 1509 L'invocazione di \ml{MP\_TAC} ($\vdash M$) applicata a un goal 1510 $(\Delta, g)$ restituisce il goal $(\Delta, M \supset g)$. Ora 1511 semplifichiamo: 1512\begin{session} 1513\begin{verbatim} 1514- e (RW_TAC arith_ss []); 1515OK.. 15162 subgoals: 1517> val it = 1518 ~prime p \/ ~(p divides FACT n + 1) 1519 ------------------------------------ 1520 0. !p. n < p ==> ~prime p 1521 1. prime p 1522 1523 ~(FACT n = 0) 1524 ------------------------------------ 1525 !p. n < p ==> ~prime p 1526\end{verbatim} 1527\end{session} 1528 Si ricordi che zero � minore di qualsiasi fattoriale, un fatto che si trova in 1529 \ml{arithmeticTheory} sotto il nome \ml{FACT\_LESS}. Cos� possiamo 1530 risolvere il goal principale per semplificazione: 1531\begin{session} 1532\begin{verbatim} 1533- e (RW_TAC arith_ss [FACT_LESS, DECIDE ``!x. ~(x=0) = 0 < x``]); 1534OK.. 1535Goal proved. ... 1536\end{verbatim} 1537\end{session} 1538Si noti l'uso `on-the-fly' di \verb+DECIDE+ per fornire una riscrittura 1539\textit{ad hoc}. Osservando il goal rimanente, si potrebbe pensare che il nostro obiettivo, di 1540dimostrare la falsit�, � andato perso. Ma questo non � vero: un goal 1541$\neg P \lor \neg Q$ � logicamente equivalente a $P \imp Q \imp \mathtt{F}$. 1542Nell'invocazione seguente, usiamo l'uguaglianza 1543$\vdash A \imp B = \neg A \lor B$ come una regola di riscrittura orientata da destra a sinistra per mezzo 1544dell'uso di \ml{GSYM}\footnote{In parole povere, \ml{GSYM} scambia i lati sinistro e 1545destro di qualsiasi equazione che trova.}. 1546\begin{session} 1547\begin{verbatim} 1548- IMP_DISJ_THM; 1549> val it = |- !A B. A ==> B = ~A \/ B : thm 1550 1551- e (RW_TAC arith_ss [GSYM IMP_DISJ_THM]); 1552OK.. 15531 subgoal: 1554> val it = 1555 ~(p divides FACT n + 1) 1556 ------------------------------------ 1557 0. !p. n < p ==> ~prime p 1558 1. prime p 1559 : goalstack 1560\end{verbatim} 1561\end{session} 1562 1563Possiamo procedere velocemente per mostrare che $p \ \mathtt{divides}\ (\mathtt{FACT}\; n)$, 1564e di conseguenza che $p = 1$, quindi che $p$ non � primo, a quel punto abbiamo finito. 1565Questo pu� essere impacchettato tutto in una singola invocazione di \ml{METIS\_TAC}: 1566\begin{session} 1567\begin{verbatim} 1568- e (METIS_TAC [DIVIDES_FACT, DIVIDES_ADDL, DIVIDES_ONE, 1569 NOT_PRIME_1, NOT_LESS, PRIME_POS]); 1570metis: r[+0+12]+0+0+0+0+0+0+0+1+1+0+0+0+0+1+1+1+1+4# 1571 1572Goal proved. 1573 [..] |- ~(p divides FACT n + 1) 1574 1575Goal proved. 1576 [.] |- ~prime p \/ ~(p divides FACT n + 1) 1577 1578Goal proved. 1579 [.] 1580|- (~(FACT n + 1 = 1) ==> ?p. prime p /\ p divides FACT n + 1) ==> F 1581 1582Goal proved. 1583 [.] |- F 1584> val it = 1585 Initial goal proved. 1586 |- !n. ?p. n < p /\ prime p : goalstack 1587\end{verbatim} 1588\end{session} 1589 Il teorema di Euclide ora � dimostrato, e possiamo riposare. Comunque, questa 1590 presentazione della dimostrazione finale sar� insoddisfacente per alcuni, 1591 dal momento che la dimostrazione � completamente nascosta nell'invocazione del 1592 ragionatore automatico. Bene allora, proviamo un'altra dimostrazione, questa volta 1593 impiegando il cosiddetto stile `asserzionale'. Quando usato in modo uniforme, 1594 questo permette una presentazione leggibile e lineare che rispecchia la 1595 dimostrazione informale. Il seguente dimostra il teorema di Euclide nello 1596 stile asserzionale. Pensiamo che sia abbastanza leggibile, certamente molto 1597 di pi� della dimostrazione standard basata su tattiche appena data\footnote{Si noti 1598 che {\tt CCONTR\_TAC}, che � utilizzata per avviare la dimostrazione, 1599 istanzia una dimostrazione per contraddizione negando il goal e 1600 spostandolo nelle ipotesi, lasciando {\tt F} come il nuovo goal.}. 1601 1602\begin{description} 1603\item [\small{({\it AGAIN\/})}] 1604\begin{tabular}[t]{l} 1605\verb+!n. ?p. n < p /\ prime p+ \\ \hline 1606\verb|CCONTR_TAC THEN | \\ 1607\verb|`?n. !p. n < p ==> ~prime p` by METIS_TAC [] THEN| \\ 1608\verb|`~(FACT n + 1 = 1)` by RW_TAC arith_ss [FACT_LESS,| \\ 1609\verb| DECIDE``~(x=0)=0<x``] THEN| \\ 1610\verb|`?p. prime p /\ | \\ 1611\verb| p divides (FACT n + 1)` by METIS_TAC [PRIME_FACTOR] THEN| \\ 1612\verb|`0 < p` by METIS_TAC [PRIME_POS] THEN| \\ 1613\verb|`p <= n` by METIS_TAC [NOT_LESS] THEN| \\ 1614\verb|`p divides FACT n` by METIS_TAC [DIVIDES_FACT] THEN| \\ 1615\verb|`p divides 1` by METIS_TAC [DIVIDES_ADDL] THEN| \\ 1616\verb|`p = 1` by METIS_TAC [DIVIDES_ONE] THEN| \\ 1617\verb|`~prime p` by METIS_TAC [NOT_PRIME_1] THEN| \\ 1618\verb|METIS_TAC []| \\ 1619\end{tabular} 1620\end{description} 1621 1622\section{Trasformare lo script in una teoria} 1623\label{sec:script-to-theory} 1624 1625Avendo dimostrato il nostro risultato, probabilmente vogliamo impacchettarlo in un modo 1626che lo renda disponibile per le sessioni future, ma che non ci richieda di 1627di passare di nuovo attraverso lo sforzo di dimostrare il teorema. Persino avere 1628uno script completo da cui sia possibile fare un copia e incolla � una 1629soluzione soggetta ad errori. 1630 1631Al fine di fare questo abbiamo bisogno un file con il nome 1632$x$\ml{Script.sml}, dove $x$ � il nome della teoria che desideriamo 1633esportare. Questo file ha quindi bisogno di essere compilato. Di fatto, usiamo realmente 1634il compilatore di Moscow ML, accuratamente aumentato con il contesto logico 1635appropriato. Comunque, il linguaggio accettato dal compilatore non � 1636esattamente lo stesso di quello accettato dal sistema interattivo, cos� abbiamo 1637bisogno di fare un poco di lavoro per smussare lo script originario nella 1638forma corretta. 1639 1640Daremo un'illustrazione di conversione a una forma che possa essere 1641compilata usando lo script 1642\[ 1643 \mbox{\ml{<holdir>/examples/euclid.sml}} 1644\] come nostra linea di base. Questo 1645file � gi� vicino ad essere nella forma corretta. Ha tutte le 1646dimostrazioni dei teoremi in una forma ``cucita'' cos� che quando eseguito, non 1647coinvolge per nulla il goal-stack. Nella sua forma data, pu� essere eseguito 1648come input per \textsf{hol} cos�: 1649 1650\setcounter{sessioncount}{0} 1651\begin{session} 1652\begin{verbatim} 1653$ cd examples/ 1654$ ../bin/hol < euclid.sml 1655 ... 1656 1657> val EUCLID = |- !n. ?p. n < p /\ prime p : thm 1658 ... 1659 1660> val EUCLID_AGAIN = |- !n. ?p. n < p /\ prime p : thm 1661- 1662\end{verbatim} 1663\end{session} 1664 1665Comunque, vogliamo creare una \ml{euclidTheory} che possiamo caricare in 1666altre sessioni interattive. Cos�, il nostro primo passo � creare un file 1667\ml{euclidScript.sml}, e copiare in esso il corpo di 1668\ml{euclid.sml} 1669 1670La prima linea non-commentata apre \ml{arithmeticTheory}. Comunque, quando 1671si scrive per il compilatore, � necessario menzionare esplicitamente gli altri 1672moduli \HOL{} da cui dipende. Dobbiamo aggiungere 1673\[ 1674\mbox{\ml{open HolKernel boolLib Parse bossLib}} 1675\] 1676La linea successiva che presenta una difficolt� � 1677\[ 1678 \mbox{\ml{set\_fixity "divides" (Infixr 450);}} 1679\] 1680Mentre � legittimo digitare espressioni direttamente nel 1681sistema interattivo, il compilatore richiede che ogni espressione di primo livello 1682sia una dichiarazione. Soddisfiamo questo requisito alterando questa linea 1683in una dichiarazione ``non fare nulla'' che non registra il risultato 1684dell'espressione: 1685\[ 1686\mbox{\ml{val \_{} = set\_fixity "divides" (Infixr 450)}} 1687\] 1688Gli unici altri cambiamenti extra sono inserire tra parentesi il resto del testo dello script 1689con le chiamate a \ml{new\_theory} e \ml{export\_theory}. Cos�, 1690prima della definizione di \ml{divides}, aggiungiamo: 1691\[ 1692\mbox{\ml{val \_{} = new\_theory "euclid";}} 1693\] 1694and at the end of the file: 1695\[ 1696\mbox{\ml{val \_{} = export\_theory();}} 1697\] 1698 1699Ora, possiamo compilare lo script che abbiamo creato usando lo 1700strumento \textsf{Holmake}. Per mantenere le cose un p� pi� ordinate, per prima cosa spostiamo 1701il nostro script in una nuova directory. 1702 1703\begin{session} 1704\begin{verbatim} 1705$ mkdir euclid 1706$ mv euclidScript.sml euclid 1707$ cd euclid 1708$ ../../bin/Holmake 1709Analysing euclidScript.sml 1710Trying to create directory .HOLMK for dependency files 1711Compiling euclidScript.sml 1712Linking euclidScript.uo to produce theory-builder executable 1713<<HOL message: Created theory "euclid".>> 1714Definition has been stored under "divides_def". 1715Definition has been stored under "prime_def". 1716Meson search level: ..... 1717Meson search level: ................. 1718 ... 1719Exporting theory "euclid" ... done. 1720Analysing euclidTheory.sml 1721Analysing euclidTheory.sig 1722Compiling euclidTheory.sig 1723Compiling euclidTheory.sml 1724\end{verbatim} 1725\end{session} 1726 1727Ora abbiamo creato quattro nuovi file, varie forme di \ml{euclidTheory} 1728con quattro differenti suffissi. Solo \ml{euclidTheory.sig} � realmente 1729adatta per un consumo da parte dell'uomo. Mentre siamo ancora nella directory 1730\ml{euclid} che abbiamo creato, possiamo provare: 1731 1732\begin{session} 1733\begin{alltt} 1734\$ ../../bin/hol 1735[...] 1736 1737[closing file "/local/scratch/mn200/Work/hol98/tools/end-init-boss.sml"] 1738- load "euclidTheory"; 1739> val it = () : unit 1740- open euclidTheory; 1741> type thm = thm 1742 val DIVIDES_TRANS = 1743 |- !a b c. a divides b /\ b divides c ==> a divides c 1744 : thm 1745 ... 1746 val DIVIDES_REFL = |- !x. x divides x : thm 1747 val DIVIDES_0 = |- !x. x divides 0 : thm 1748\end{alltt} 1749\end{session} 1750 1751\section{Sommario} 1752 1753Il lettore ora ha visto un teorema interessante dimostrato, in grande dettaglio, 1754in \holn{}. La discussione ha illustrato gli strumenti di alto livello forniti in 1755\ml{bossLib} e ha toccato questioni che includono la selezione degli strumenti, l'undo, 1756la `levigatura delle tattiche', la semplificazione esplorativa, e la `biforcazione' di 1757nuovi tentativi di dimostrazione. Abbiamo anche tentato di dare un'idea dei processi di 1758pensiero che un utente potrebbe impiegare. Ci� che segue � una raccolta pi� o meno 1759casuale di altre osservazioni. 1760\begin{itemize} 1761 1762\item Nonostante la dimostrazione del teorema di Euclide sia breve e semplice da 1763comprendere quando presentata in modo informale, � stata richiesta una quantit� 1764forse sorprendente di sviluppo a supporto dell'impostazione dell'argomento 1765classico di Euclide. 1766 1767\item Il supporto alla dimostrazione fornito da \ml{bossLib} 1768(\verb+RW_TAC+, \ml{METIS\_TAC}, \ml{DECIDE\_TAC}, \ml{DECIDE}, 1769\ml{Cases\_on}, \ml{Induct\_on}, e dal costrutto ``\ml{by}'') � stato 1770quasi completo per questo esempio: raramente � stato necessario ricorrere a 1771tattiche di basso livello. 1772 1773\item La semplificazione � un cavallo di battaglia delle tattiche; persino quando � stato usato 1774un ragionatore automatico come \ml{METIS\_TAC}, la sua applicazione � stata spesso 1775preparata da qualche semplificazione esplorativa. Vale la pena quindi prendere 1776confidenza con i punti di forza e di debolezza del semplificatore. 1777 1778\item Un problema comune con i sistemi interattivi di dimostrazione � trattare con 1779le ipotesi. Spesso \ml{METIS\_TAC} e il costrutto ``\ml{by}'' permettono 1780di usare le ipotesi senza ricorrere direttamente alla loro indicizzazione 1781(o al dar loro un nome, che equivale alla stessa cosa). Questo � desiderabile, 1782dal momento che le ipotesi sono concettualmente un {\it insieme}, e inoltre, 1783l'esperienza ha mostrato che il proliferare dell'indicizzazione nelle ipotesi risulta in 1784script di dimostrazione difficili da manutenere. Comunque, pu� confondere lavorare con 1785un grande insieme di ipotesi, nel qual caso i seguenti approcci possono essere 1786utili. 1787 1788Ci si pu� riferire direttamente alle ipotesi usando \ml{UNDISCH\_TAC} (rende 1789l'ipotesi designata l'antecedente del goal), 1790\ml{ASSUM\_LIST} (fornisce l'intera lista delle ipotesi a una tattica), 1791\ml{POP\_ASSUM} (da la prima ipotesi a una tattica), e 1792\ml{PAT\_ASSUM} (da a una tattica la prima ipotesi 1793{\it che soddisfa il matching\/}). (Si veda \REFERENCE{} per maggiori dettagli su tutte queste cose.) 1794I numeri associati alle ipotesi dal gestore di dimostrazione verosimilmente potrebbero 1795essere usati per accedere alle ipotesi (sarebbe piuttosto semplice scrivere una 1796tattica simile). Comunque, iniziare una nuova dimostrazione � a volte la 1797cosa pi� illuminante da fare. 1798 1799In alcuni casi, � utile essere in grado di cancellare un'ipotesi. Questo si pu� 1800ottenere passando l'ipotesi a una tattica che la ignora. 1801Per esempio, per scartare la prima ipotesi, si pu� invocare 1802\ml{POP\_ASSUM (K ALL\_TAC)}. 1803 1804\item Nell'esempio, non abbiamo usato le caratteristiche pi� avanzate di 1805\ml{bossLib}, in gran parte perch� non forniscono, finora, molte pi� 1806funzionalit� rispetto alla semplice sequenza di semplificazione, procedure 1807di decisione, e ragionamento automatico al primo ordine. Il tatticale 1808\ml{THEN} � dunque servito come una sostituzione adeguata. Nel futuro, 1809questi punti d'ingresso dovrebbero diventare pi� potenti. 1810 1811\item E' quasi sempre necessario avere un'idea della dimostrazione {\it 1812 informale\/} al fine di avere successo quando di fa una dimostrazione 1813 formale. Tuttavia, troppo spesso i novizi adottano la seguente 1814 strategia: (1) riscrivere il goal con alcune definizioni rilevanti, e 1815 quindi (2) fare affidamento sulla sintassi del goal risultante per guidare 1816 la selezione delle tattiche successive. Un tale approccio costituisce un chiaro 1817 caso di cane che si morde la coda, ed � una strategia povera da adottare. 1818 La comprensione della struttura di alto livello della dimostrazione � uno dei 1819 fattori pi� importanti negli esercizi di verifica di successo. 1820 1821L'autore ha notato che molti degli esperti di verifica pi� di successo 1822lavorano usando un foglio di carta per tenere traccia dei passi principali che 1823devono essere fatti. Forse distogliere lo sguardo sulla carte aiuta a rompere 1824l'effetto ipnotizzante dello schermo del computer. 1825 1826Dall'altra parte, uno dei vantaggi di avere una logica meccanizzata 1827� che la macchina pu� essere usata come un calcolatore di espressioni formali, 1828e cos� l'utente lo pu� usare per esplorare velocemente e accuratamente varie 1829possibilit� di dimostrazione. 1830 1831\item Gli strumenti molto potenti come \ml{METIS\_TAC}, \ml{DECIDE\_TAC}, e 1832\ml{RW\_TAC} sono il modo principale per fare progressi in una dimostrazione in 1833\ml{bossLib}. In molti casi, essi fanno ci� che si desidera, o addirittura 1834riescono a stupire l'utente con la loro potenza. Nella formalizzazione del 1835teorema di Euclide, gli strumenti hanno funzionato piuttosto bene. Tuttavia, a volte 1836sono eccessivamente aggressivi, o semplicemente fanno errori. In questi casi, si devono 1837usare, o persino scrivere, degli strumenti di dimostrazione pi� specializzati, e di conseguenza 1838alla fine bisogna imparare il supporto sottostante a \ml{bossLib}. 1839 1840\item Avere una buona conoscenza dei lemmi disponibile, e di dove essi 1841si trovano, � una parte essenziale per avere successo. Spesso gli strumenti 1842potenti possono sostituire i lemmi in un dominio ristretto, ma in generale, si 1843deve sapere cosa � stato gi� dimostrato. Abbiamo visto che i punti di ingresso 1844in \verb+DB+ aiutano a trovare velocemente i lemmi. 1845 1846\end{itemize} 1847 1848 1849%%% Local Variables: 1850%%% mode: latex 1851%%% TeX-master: "tutorial" 1852%%% End: 1853