Verificação Formal de Software

3.6. Enunciados de Teoremas🔗

Um theorem é uma definição cujo tipo é uma proposição. Enunciá-lo não exige prova; o marcador sorry fica onde a prova entrará, e Lean assinala cada uso dele. Os enunciados abaixo especificam as funções desta aula, e o espaço de nomes evita que seus nomes colidam com os de Mathlib.

namespace SorryTheorems theorem declaration uses `sorry`add_comm (m n : ) : add m n = add n m := m:n:add m n = add n m All goals completed! 🐙 theorem declaration uses `sorry`add_assoc (l m n : ) : add (add l m) n = add l (add m n) := l:m:n:add (add l m) n = add l (add m n) All goals completed! 🐙 theorem declaration uses `sorry`mul_comm (m n : ) : mul m n = mul n m := m:n:mul m n = mul n m All goals completed! 🐙 theorem declaration uses `sorry`mul_assoc (l m n : ) : mul (mul l m) n = mul l (mul m n) := l:m:n:mul (mul l m) n = mul l (mul m n) All goals completed! 🐙 theorem declaration uses `sorry`mul_add (l m n : ) : mul l (add m n) = add (mul l m) (mul l n) := l:m:n:mul l (add m n) = add (mul l m) (mul l n) All goals completed! 🐙 theorem declaration uses `sorry`reverse_reverse {α : Type} (xs : List α) : reverse (reverse xs) = xs := α:Typexs:List αreverse (reverse xs) = xs All goals completed! 🐙 end SorryTheorems

A computação não os prova. rfl resolve add 2 7 = add 7 2, pois os dois lados computam para 9, mas em add m n = add n m as variáveis bloqueiam a computação, e a lei geral precisa de indução estrutural, o assunto das próximas aulas.

Os axiomas são a outra maneira de afirmar sem provar, e merecem mais desconfiança. Uma constante opaque tem tipo e nenhuma definição, e um axiom afirma uma proposição sem prova nenhuma. Nada o verifica, então um axioma inconsistente quebra silenciosamente todo o desenvolvimento. A disciplina enuncia axiomas apenas para discuti-los.

opaque a : opaque b : axiom a_less_b : a < b

3.6.1. Exemplos🔗

Os exemplos abaixo releem os enunciados, separam o que a computação resolve do que ela não resolve e rastreiam de quais axiomas uma prova depende. O espaço de nomes MoreTheorems mantém os nomes novos longe dos de Mathlib.

Exemplo 1. Um enunciado com parâmetros nomeados é uma proposição universalmente quantificada.

SorryTheorems.add_comm : (m n : ), add m n = add n m#check @SorryTheorems.add_comm
SorryTheorems.add_comm :  (m n : ), add m n = add n m

Exemplo 2. Um parâmetro implícito aparece entre chaves, e o enunciado quantifica também sobre o tipo.

@SorryTheorems.reverse_reverse : {α : Type} (xs : List α), reverse (reverse xs) = xs#check @SorryTheorems.reverse_reverse
@SorryTheorems.reverse_reverse :  {α : Type} (xs : List α), reverse (reverse xs) = xs

Exemplo 3. O comando #print axioms informa em que uma prova se apoia, e sorry deixa o rastro sorryAx.

'SorryTheorems.add_comm' depends on axioms: [sorryAx]#print axioms SorryTheorems.add_comm
'SorryTheorems.add_comm' depends on axioms: [sorryAx]

Exemplo 4. Uma lei que a computação resolve dispensa indução. O zero à direita casa a primeira equação de add, então rfl a prova para todo n.

namespace MoreTheorems theorem add_zero_right (n : ) : add n 0 = n := rfl end MoreTheorems 'MoreTheorems.add_zero_right' does not depend on any axioms#print axioms MoreTheorems.add_zero_right
'MoreTheorems.add_zero_right' does not depend on any axioms

Exemplo 5. O mesmo vale para a primeira equação de eval, qualquer que seja o ambiente.

namespace MoreTheorems theorem eval_num (env : String ) (i : ) : eval env (AExp.num i) = i := rfl end MoreTheorems MoreTheorems.eval_num : (env : String ) (i : ), eval env (AExp.num i) = i#check @MoreTheorems.eval_num
MoreTheorems.eval_num :  (env : String  ) (i : ), eval env (AExp.num i) = i

Exemplo 6. Uma equação fechada merece um nome tanto quanto uma lei geral.

namespace MoreTheorems theorem fib_seven : fib 7 = 13 := rfl theorem reverse_nil : reverse ([] : List ) = [] := rfl end MoreTheorems

Exemplo 7. Ligadores à esquerda dos dois-pontos e um ∀ explícito enunciam a mesma proposição.

namespace MoreTheorems theorem all_add_zero : n : , add n 0 = n := fun _ => rfl end MoreTheorems MoreTheorems.all_add_zero : (n : ), add n 0 = n#check @MoreTheorems.all_add_zero
MoreTheorems.all_add_zero :  (n : ), add n 0 = n

Exemplo 8. Aplicar um teorema enunciado a argumentos instancia o enunciado, exista ou não uma prova.

SorryTheorems.add_comm 2 3 : add 2 3 = add 3 2#check SorryTheorems.add_comm 2 3
SorryTheorems.add_comm 2 3 : add 2 3 = add 3 2

Exemplo 9. #print axioms mostra tudo o que uma prova usa. A prova abaixo se apoia no axioma desta seção e em propext, usado pelo lema de Mathlib.

namespace MoreTheorems theorem a_ne_b : a b := ne_of_lt a_less_b end MoreTheorems 'MoreTheorems.a_ne_b' depends on axioms: [a_less_b, propext]#print axioms MoreTheorems.a_ne_b
'MoreTheorems.a_ne_b' depends on axioms: [a_less_b, propext]

Exemplo 10. As variáveis bloqueiam a computação, então a lei abaixo espera pela indução estrutural e carrega sorryAx enquanto isso.

namespace MoreTheorems theorem declaration uses `sorry`half_double (n : ) : half (add n n) = n := n:half (add n n) = n All goals completed! 🐙 end MoreTheorems 'MoreTheorems.half_double' depends on axioms: [sorryAx]#print axioms MoreTheorems.half_double
'MoreTheorems.half_double' depends on axioms: [sorryAx]