Você está na página 1de 11

Capı́tulo 3

Provas por indução estrutural

Indução estrutural é uma técnica de prova bastante comum no estudo de linguagens de programação. Ela é
empregada quando queremos provar que uma determinada propriedade é verdadeira para todos os elementos
de um conjunto definido de maneira indutiva, como é o caso do conjunto de ASTs de L0, e também de árvores
de derivação de tipo, árvores de derivação da semântica operacional big-step ou árvores de derivação (de um
passo) da semântica operacional small-step.
Uma prova de que todos os elementos de um conjunto infinito definido indutivamente possuem uma deter-
minada propriedade P , consiste em provar que P vale para todos os elementos básicos (sem sub-estruturas)
e provar que, se P vale para as sub-estruturas de um certa estrutura, então P também vale para a estrutura.

3.1 Formato de provas por indução estrutural


Vamos considerar indução estrutural para um contexto mais simples dos números naturais antes de considerá-lo
em provas de propriedades de L0.
O conjunto N pode ser definido de forma indutiva pela seguinte gramática abstrata:

n ::= 0 | succ(n)

Trata-se de um conjunto infinito mas com uma quantidade finita de construtores de elementos: 0 e succ.
O 0 é um construtor de aridade zero, e succ é um construtor de aridade 1. Aplicado a um elemento de N já
construı́do, succ gera um novo elemento de N.
Para provarmos que todos os elementos do conjunto N possuem um determinada propriedade P , ou seja
para provarmos que ∀n ∈ N. P (n), é preciso fazer o seguinte:

• provar que construtor básico, ou seja 0, satisfaz P , ou seja, provar P (0), e

• provar que o construtor succ preserva a propriedade P quando aplicado a um elemento que possui
a propriedade P . Ou seja, é preciso provar que, se succ recebe um elemento qualquer n que possui
a propriedade P , então o elemento succ(n) também possui a propriedade P . Em outras palavras, é
preciso provar a seguinte fórmula ∀n ∈ N. P (n) ⇒ P (succ(n)).

Isso nos leva seguinte regra de dedução natural para indução estrutural para N:

P (0) ∀n ∈ N. P (n) ⇒ P (succ(n))


(IndEstrNat)
∀n ∈ N. P (n)

Para provarmos a segunda premissa, é preciso provar que a implicação P (n) ⇒ P (succ(n)) é verdadeira
para qualquer n ∈ N (ou seja a prova de P (n) ⇒ P (succ(n)) não pode depender de outra propriedade de n).

21
E a prova da implicação P (n) ⇒ P (succ(n)) consiste em provar o consequente P (succ(n)) podendo fazer
uso do antecedente P (n), também chamado de hipótese indutiva. Em resumo: o esforço de prova para provar
∀n ∈ N. P (n) consiste em:

1. provar P (0)

2. provar P (succ(n)) - podendo fazer uso da hipótese indutiva P (n), caso necessário (e cuidar que essa
prova não dependa de alguma outra suposição a cerca de n)

3.2 Prova por indução estrutural para L0


Abaixo segue a regra de inferência para indução estrutural da linguagem L0 (no estilo de dedução natural):

∀e1 , e2 , e3 ∈ L0. P (e1 ) ∧ P (e2 ) ∧ P (e3 ) ⇒ P (if(e1 , e2 , e3 ))


P (true) ∀e ∈ L0. P (e) ⇒ P (succ(e)
P (false) ∀e ∈ L0. P (e) ⇒ P (pred(e)
P (0) ∀e ∈ L0. P (e) ⇒ P (iszero(e)
∀e ∈ L0. P (e)

As três premissas empilhadas no lado esquerdo são chamadas de base da indução. As quatro premissas
empilhadas no lado direito da regra acima são chamadas de passos indutivos.
Para provar cada uma das fórmulas correspondentes aos passos indutivos usamos a regra de dedução
natural introdução do ∀ (nome apropriado quando lida ”de cima para baixo”). Por exemplo, para provarmos
a premissa
∀e1 , e2 , e3 . P (e1 ) ∧ P (e2 ) ∧ P (e3 ) ⇒ P (if(e1 , e2 , e3 ))

precisamos provar a fórmula

P (e1 ) ∧ P (e2 ) ∧ P (e3 ) ⇒ P (if(e1 , e2 , e3 ))

e essa prova não pode depender de outras hipóteses sobre e1 , e2 e e3 . Esta fórmula, por sua vez, é uma
implicação. Para prová-la (usando a regra de dedução natural introdução da implicação) temos que provar o
consequente P (if(e1 , e2 , e3 )), podendo fazer uso do antecedente P (e1 ) ∧ P (e2 ) ∧ P (e3 ), caso necessário.

Note que o antecedente da implicação diz que e1 , e2 e e3 possuem a propriedade P . Dizemos que P (e1 ),
P (e2 ) e P (e3 ) são hipóteses indutivas (HI).

Ou seja, o esforço de prova está em provar P (if(e1 , e2 , e3 )), podendo fazer uso das hipóteses indutivas
P (e1 ), P (e2 ) e P (e3 ), caso necessário. Raciocı́nio semelhante se aplica na prova dos demais passos indutivos.

Em resumo: para provar que ∀e. P (e) é preciso fazer as seguintes subprovas abaixo (é uma boa prática
ordenar os casos abaixo de acordo com a ordem em que as expressões aparecem na gramática):

1. provar P (true)

2. provar P (false)

3. provar P (if(e1 , e2 , e3 )) - podendo fazer uso das HI P (e1 ), P (e2 ) e P (e3 )

4. provar P (0)

5. provar P (succ(e)) - podendo fazer uso da HI P (e)

22
6. provar P (pred(e)) - podendo fazer uso da HI P (e)

7. provar P (iszero(e)) - podendo fazer uso da HI P (e)

E claro, as provas podem fazer uso não só das hipóteses indutivas, mas também de todo conhecimento
prévio que não precisa estar explicitado no enunciado do teorema.

As provas por indução na estrutura de expressões de L0 de teoremas ∀e. P (e) têm todas a seguinte forma:

Teorema (nome do teorema) ∀e. P (e)

Prova. Por indução na estrutura de e.

caso true

aqui vai a prova de P (true)

caso false

aqui vai a prova de P (false)

caso if(e1 , e2 , e3 )

aqui vai a prova de P (if(e1 , e2 .e3 )) (pode usar as HIs P (e1 ), P (e2 ), P (e3 ))

caso 0

aqui vai a prova de P (0)

caso succ(e)

aqui vai a prova de P (succ(e)) que pode fazer uso da HI P (e)

caso pred(e)

aqui vai a prova de P (pred(e)) que pode fazer uso da HI P (e)

caso iszero(e)

aqui vai a prova de P (iszero(e)) que pode fazer uso da HI P (e) 

Observe que há sete construtores de expressões na linguagem L0. A estrutura de prova por indução na
estrutura sintática das expressões possui um caso para cada um desses construtores.

Exercı́cio 18. Reescreva a regra de dedução natural para indução estrutural sobre expressões de L0 estendida
com expressões and(e1 , e2 ), or(e1 , e2 ),e not(e).

23
3.3 Exemplo de prova por indução estrutural - Teorema do Progresso
Abaixo segue a prova do Teorema do Progresso para L0. Observe a prova é apresentada em um nı́vel de
detalhamento bem maior do que o usual.

Teorema 5 (Progresso). Se e : T então (i) e é valor ou (ii) existe e0 tal que e −→ e0 .


(ou seja: ∀e. ∀T. e : T ⇒ (valor(e) ∨ ∃e0 . e −→ e0 ).

Prova. Por indução na estrutura de e. ( P (e) ≡ ∀T. e : T ⇒ (valor( e ) ∨ ∃e0 . e −→ e0 ).)

caso true
(prova de P (true) ou seja prova de ∀T. true : T ⇒ (valor(true) ∨ ∃e0 . true −→ e0 ).)

Após a aplicação da regra ∀I na fórmula acima, temos que provar a seguinte fórmula:

true : T ⇒ (valor(true) ∨ ∃e0 . true −→ e0 ) (3.1)

Pela regra ⇒ I aplicada a fórmula (3.1) acima assumimos true : T e temos que provar

valor(true) ∨ ∃e0 . true −→ e0

Que é trivialmente verdadeira pois valor(true) é verdadeiro.

caso false
(prova de P (false) ou seja prova de ∀T. false : T ⇒ (valor(false) ∨ ∃e0 . false −→ e0 ).)

Essa prova segue exatamente a mesma estrutura do caso anterior trocando true por false.

caso if(e1 , e2 , e3 )
(prova de P (if(e1 , e2 , e3 )) ou seja prova de: ∀T. if(e1 , e2 , e3 ) : T ⇒ (valor(if(e1 , e2 , e3 )) ∨ ∃e0 . if(e1 , e2 , e3 ) −→ e0 ).

podendo usar as seguintes hipóteses indutivas, caso necessário:

HI para e1 : P (e1 ) ≡ ∀T. e1 : T ⇒ (valor(e1 ) ∨ ∃e0 . e1 −→ e0 ),

HI para e1 : P (e2 ) ≡ ∀T. e2 : T ⇒ (valor(e2 ) ∨ ∃e0 . e2 −→ e0 ),

HI para e1 : P (e3 ) ≡ ∀T. e3 : T ⇒ (valor(e3 ) ∨ ∃e0 . e3 −→ e0 ))

Após a aplicação da regra ∀I na fórmula acima, temos que provar a seguinte fórmula:

if(e1 , e2 , e3 ) : T ⇒ (valor(if(e1 , e2 , e3 )) ∨ ∃e0 . if(e1 , e2 , e3 ) −→ e0 ) (3.2)

Pela regra ⇒ I aplicada a (3.2) acima assumimos:

if(e1 , e2 , e3 ) : T (3.3)

e temos que provar


valor(if(e1 , e2 , e3 )) ∨ ∃e0 . if(e1 , e2 , e3 ) −→ e0

24
Como valor(if(e1 , e2 , e3 )) é evidentemente falso, para provar essa disjunção acima temos que provar:

∃e0 . if(e1 , e2 , e3 ) −→ e0 (3.4)

De (3.3) acima e pela regra de tipo T-If temos que:

e1 : bool (3.5)

Pela hipótese indutiva para e1 e pela regra ∀E (instanciando T com bool) temos:

e1 : bool ⇒ (valor(e1 ) ∨ ∃e0 . e1 −→ e0 ) (3.6)

Por modus ponens com (3.5) e (3.6) acima temos:

valor(e1 ) ∨ ∃e0 . e1 −→ e0 (3.7)

Por ∨E, para provar (3.4) a partir de (3.7) temos que provar (3.4) a partir de cada um dos disjuntos de (3.7):

subcaso valor(e1 ):

Por (3.5) e pelas regras do sistema de tipos temos que e1 = true ou e1 = false.

Se e1 = true: pela regra E-IfTrue com e1 = true como premissa temos que:

if(e1 , e2 , e3 ) −→ e2 (3.8)

Por (3.8) acima e pela regra ∃I provamos, como desejado, que:

∃e0 . if(e1 , e2 , e3 ) −→ e0

Se e1 = false: pela regra E-IfFalse com e1 = false como premissa temos que:

if(e1 , e2 , e3 ) −→ e3 (3.9)

Por (3.9) acima e pela regra ∃I provamos, como desejado, que:

∃e0 . if(e1 , e2 , e3 ) −→ e0

subcaso ∃e0 . e1 −→ e0 :

Pela regra ∃E usando e01 como elemento representativo, temos que

e1 −→ e01 (3.10)

Com (3.10) como premissa para a regra E-If temos que:

if(e1 , e2 , e3 ) −→ if(e01 , e2 , e3 ) (3.11)

25
E por (3.11) e pela regra ∃I provamos como desejado que:

∃e0 . if(e1 , e2 , e3 ) −→ e0

caso 0
prova de P (0) ou seja prova de ∀T. 0 : T ⇒ (valor(0) ∨ ∃e0 . 0 −→ e0 ).

Essa prova segue exatamente a mesma estrutura do caso para true, trocando true por 0.

caso succ(e)
(prova de P (succ(e)) ou seja prova de: ∀T. succ(e) : T ⇒ (valor(succ(e)) ∨ ∃e0 . succ(e) −→ e0 ).

podendo usar a seguinte hipótese indutiva, caso necessário: P (e) ≡ ∀T. e : T ⇒ (valor(e) ∨ ∃e0 . e −→ e0 )

Após a aplicação da regra ∀I na fórmula acima, temos que provar a seguinte fórmula:

succ : T ⇒ (valor(succ(e)) ∨ ∃e0 . succ(e) −→ e0 ) (3.12)

Pela regra ⇒ I aplicada a (3.12) acima assumimos:

succ(e) : T (3.13)

e temos que provar


valor(succ(e)) ∨ ∃e0 . succ(e) −→ e0 (3.14)

De (3.13) acima e pela regra de tipo T-Succ temos que:

e : nat (3.15)

Pela hipótese indutiva para e e pela regra ∀E (instanciando T com nat) temos:

e : nat ⇒ (valor(e) ∨ ∃e0 . e −→ e0 ) (3.16)

Por modus ponens com (3.15) e (3.16) acima temos:

valor(e) ∨ ∃e0 . e −→ e0 (3.17)

Por ∨E, para provar (3.14) a partir de (3.17) temos que provar (3.14) a partir de cada um dos seus disjuntos:

subcaso valor(e):

Por (3.15) e pelas regras do sistema de tipos temos que e = 0 ou e = succ(nv) onde nv é valor numérico.
Em ambos os casos temos que valor(succ(e)) é verdadeiro provando assim (3.14).

subcaso ∃e0 . e −→ e0 :

Pela regra ∃E usando e0 como elemento representativo, temos que

e −→ e0 (3.18)

26
Com (3.18) como premissa para a regra E-Succ temos que:

succ(e) −→ succ(e0 ) (3.19)

E por (3.19) e pela regra ∃I provamos como desejado que

∃e0 . succ(e) −→ e0

caso pred(e)
prova de P (pred(e)) ou seja prova de: ∀T. pred(e) : T ⇒ (valor(pred(e)) ∨ ∃e0 . pred(e) −→ e0 ).

podendo usar a seguinte hipótese indutiva, caso necessário: P (e) ≡ ∀T. e : T ⇒ (valor(e) ∨ ∃e0 . e −→ e0 )

Após a aplicação da regra ∀I na fórmula acima, temos que provar a seguinte fórmula:

pred(e) : T ⇒ (valor(pred(e)) ∨ ∃e0 . pred(e) −→ e0 ) (3.20)

Pela regra ⇒ I aplicada a (3.20) acima assumimos:

pred(e) : T (3.21)

e temos que provar


valor(pred(e)) ∨ ∃e0 . pred(e) −→ e0

Como valor(pred(e)) é evidentemente falso para provar essa disjunção acima temos que provar:

∃e0 . pred(e) −→ e0 (3.22)

De (3.21) acima e pela regra de tipo T-Pred temos que:

e : nat (3.23)

Pela hipótese indutiva para e e pela regra ∀E (instanciando T com nat) temos:

e : nat ⇒ (valor(e) ∨ ∃e0 . e −→ e0 ) (3.24)

Por modus ponens com (3.23) e (3.24) acima temos:

valor(e) ∨ ∃e0 . e −→ e0 (3.25)

Por ∨E, para provar (3.22) a partir de (3.25) temos que provar (3.22) a partir de cada um dos seus disjuntos:

subcaso valor(e):

Por (3.23) e pelas regras do sistema de tipos temos que e = 0 ou e = succ(nv) com nv um valor numérico.

Se e = 0: pela regra E-PredZero com e = 0 temos que:

pred(e) −→ 0 (3.26)

27
Por (3.26) acima e pela regra ∃I provamos, como desejado, que:

∃e0 . pred(e) −→ e0

Se e = succ(nv): pela regra E-PredSucc com e = succ(nv) temos que:

pred(e) −→ nv (3.27)

Por (3.27) acima e pela regra ∃I provamos, como desejado, que:

∃e0 . pred(e) −→ e0

subcaso ∃e0 . e −→ e0 :

Pela regra ∃E usando e0 como elemento representativo, temos que

e −→ e0 (3.28)

Com (3.28) como premissa para a regra E-Pred temos que:

pred(e) −→ pred(e0 ) (3.29)

E por (3.29) e pela regra ∃I provamos como desejado que;

∃e0 . pred(e) −→ e0

caso iszero(e)
prova de P (iszero(e)) ou seja prova de: ∀T. iszero(e) : T ⇒ (valor(iszero(e)) ∨ ∃e0 . iszero(e) −→ e0 ).

podendo usar a seguinte hipótese indutiva, caso necessário: P (e) ≡ ∀T. e : T ⇒ (valor(e) ∨ ∃e0 . e −→ e0 )

Após a aplicaçao da regra ∀I na fórmula acima, temos que provar a seguinte fórmula:

iszero(e) : T ⇒ (valor(iszero(e)) ∨ ∃e0 . iszero(e) −→ e0 ) (3.30)

Pela regra ⇒ I aplicada a (3.30) acima assumimos:

iszero(e) : T (3.31)

e temos que provar


valor(iszero(e)) ∨ ∃e0 . iszero(e) −→ e0

Como valor(iszero(e)) é evidentemente falso para provar essa disjunção acima temos que provar:

∃e0 . iszero(e) −→ e0 (3.32)

De (3.31) acima e pela regra de tipo T-IsZero temos que:

e : nat (3.33)

28
Pela hipótese indutiva para e e pela regra ∀E (instanciando T com nat) temos:

e : nat ⇒ (valor(e) ∨ ∃e0 . e −→ e0 ) (3.34)

Por modus ponens com (3.33) e (3.34) acima temos:

valor(e) ∨ ∃e0 . e −→ e0 (3.35)

Por ∨E, para provar (3.32) a partir de (3.35) temos que provar (3.32) a partir de cada um dos seus disjuntos:

subcaso valor(e):

Por (3.33) e pelas regras do sistema de tipos temos que e = 0 ou e = succ(nv) com nv um valor numérico.

Se e = 0: pela regra E-IsZeroZero com e = 0 temos que:

iszero(e) −→ true (3.36)

Por (3.36) acima e pela regra ∃I provamos, como desejado, que:

∃e0 . iszero(e) −→ e0

Se e = succ(nv): pela regra E-IsZeroSucc com e = succ(nv) temos que:

iszero(e) −→ false (3.37)

Por (3.37) acima e pela regra ∃I provamos, como desejado, que:

∃e0 . iszero(e) −→ e0

subcaso ∃e0 . e −→ e0 :

Pela regra ∃E usando e0 como elemento representativo, temos que

e −→ e0 (3.38)

Com (3.38) como premissa para a regra E-IsZero temos que:

iszero(e) −→ iszero(e0 ) (3.39)

E por (3.39) e pela regra ∃I provamos como desejado que: ∃e0 . iszero(e) −→ e0 

Agora veremos uma versão mais compacta da mesma prova. Nesta versão, detalhes do uso das regras de
dedução natural serão omitidos. De agora em diante adotaremos o estilo mais compacto de apresentar provas.

29
Teorema 5 (Progresso). Se e : T então (i) e é valor ou (ii) existe e0 tal que e −→ e0 .

Prova. Por indução na estrutura de e.

caso true, false, 0 trivial pois true, false e 0 são valores.

caso if(e1 , e2 , e3 ) Pela suposição de que ` if(e1 , e2 , e3 ) : T e pela regra de tipo T-If temos que
` e1 : bool. Pela hipótese indutiva para e1 temos que e1 é valor ou existe e’ tal que e1 −→ e0 . Para ambas
as possibilidades vamos provar que if(e1 , e2 , e3 ) progride.

Assumindo e1 é valor: como ` e1 : bool, pelas regras do sistema de tipos temos que e1 = true ou e1 = false.
Se e1 = true, pela regra E-IfTrue temos que if(e1 , e2 , e3 ) −→ e2 . Se e1 = false, pela regra E-IfFalse
temos que if(e1 , e2 , e3 ) −→ e3 .

Assumindo que existe e0 tal que e1 −→ e0 : podemos afirmar que, para algum e01 , e1 −→ e01 . Logo, pela regra
E-If, concluimos que if(e1 , e2 , e3 ) −→ if(e01 , e2 , e3 ).

caso succ(e) Pela suposição de que ` succ(e) : T e pela regra de tipo T-Succ temos que ` e : nat. Pela
hipótese indutiva para e temos que e é valor ou existe e0 tal que e −→ e0 .

Assumindo e é valor: como ` e : nat, pelas regras do sistema de tipos temos que e = 0 ou e = succ(nv) com
nv um valor numérico. Em ambos os casos temos que succ(e) é um valor.

Assumindo existe e0 tal que e −→ e0 : podemos afirmar que, para algum e0 , e −→ e0 . Logo, pela regra
E-Succ, concluimos que succ(e) −→ succ(e0 ).

caso pred(e) Pela suposição de que ` pred(e) : T e pela regra de tipo T-PRED temos que ` e : nat.
Pela hipótese indutiva para e temos que e é valor ou existe e0 tal que e −→ e0 . Para ambas as possibilidades
vamos provar que pred(e) progride.

Assumindo e é valor: como ` e : nat, pelas regras do sistema de tipos temos que e = 0 ou e = succ(nv) com
nv um valor numérico. Se e = 0, pela regra E-PredZero temos que pred(e) −→ 0. Se e = succ(nv), pela
regra E-PredSucc temos que pred(succ(nv)) −→ nv.

Assumindo ∃e0 . e −→ e0 : podemos afirmar que, para algum e0 , e −→ e0 . Logo, pela regra E-Pred concluimos
que pred(e) −→ pred(e0 ).

caso iszero(e) Pela suposição de que ` iszero(e) : T e pela regra de tipo T-ISZERO temos que
` e : nat. Pela hipótese indutiva para e temos que e é valor ou existe e0 tal que e −→ e0 . Para ambas as
possibilidades vamos provar que iszero(e) progride.

Assumindo e é valor: como ` e : nat, pelas regras do sistema de tipos temos que e = 0 ou e = succ(nv)
com nv um valor numérico. Se e = 0, pela regra E-IsZeroZero temos que iszero(e) −→ true. Se
e = succ(nv), pela regra E-IsZeroSucc temos que iszero(succ(nv)) −→ false.

Assumindo ∃e0 . e −→ e0 : podemos afirmar que, para algum e0 , e −→ e0 . Logo, pela regra E-IsZero,
concluimos que iszero(e) −→ iszero(e0 ). 

30
Exercı́cio 19. Prove os teoremas 2 (determinismo) e 4 (unicidade de tipo) do capı́tulo anterior usando indução
estrutural.

Exercı́cio 20. Prove o Teorema da Preservação por indução na estrutura de expressões de L0

Exercı́cio 21. Prove, por indução na estrutura de expressões, que o algoritmo de inferência de tipos para L0
é seguro e completo.

31

Você também pode gostar