Lean
Usamos o proof assistant Lean para algumas atividades obrigatórias.
Este FAQ ainda é sobre o Lean 3, mas nos vamos usar o Lean 4. Estarei atualizando esta página nos primeiros dias do semestre.
- Instale o Lean no teu computador Seguindo os links lá, se tu usa Windows, dê uma olhada no vídeo Installing the Lean theorem prover (windows) no YouTube.
- Configure teu editor para ativar o modo Lean
- Numa pasta no teu computador use o comando leanpkg new fmclean(Isso vai criar uma nova pasta chamadafmcleane iniciar um repositório git nela.)
- Cada vez que você trabalha em qualquer arquivo dentro do teu repositório git, não esqueça de
commit’ar teu trabalho imediatamente, mesmo sendo um progresso pequeno;
e faça pushimediatamente: é teu “comprovante” que tal dia fez tal trabalho!
Como posso compartilhar meu código para receber feedback ou tirar uma dúvida?
- Se teu código é «stand-alone», usando ```leanpara iniciar o bloco de código no Zulip, já ativa o link para o Lean playground.
- Alternativamente podes compartilhar teu repo no github (que já deve ser visível no teu profile no Zulip!)
Se meu alvo é uma implicação P ⇒ Q
Texto: «Suponha P.»
Lean: intro hp, onde hp é o nome que escolhemos para rotular esse dado.
Efeitos:
- ganhamos o P nos dados
- o alvo vira Q
Se meu alvo é uma conjunção P & Q
Texto: «Parte P: [demonstro P aqui]. Parte Q: [demonstro Q aqui].»
Lean: split,
Efeitos: nossa demonstração separa em duas partes, copiando/colando os dados atuais e: a primeira parte tem como alvo P, a segunda parte tem com alvo Q. Precisamos demonstrar ambas as partes.
Se meu alvo é uma disjunção P ∨ Q
Tenho o direito de escolher a parte esquerda (P) ou a parde direita (Q). Tenho então de escolher uma das duas alternativas:
- 
Texto 1: «Escolho a esquerda para demonstrar.» Mais humano: «Vou demonstrar P.» 
 Lean 1:left,
 Efeito 1: O alvo vira P.
- 
Texto 2: «Escolho a direita para demonstrar.» Mais humano: «Vou demonstrar Q.» 
 Lean 2:right,
 Efeito 2: O alvo vira Q.
Se meu alvo é uma proposição universal (∀x:A)[ φ(x) ]
Basta solicitar um arbitrio objeto a do tipo A e demonstrar que φ(a).
Texto: «Seja a : A.»  Efeito: O alvo vira φ(a).
Lean: intro a,
Se meu alvo é uma proposição existencial (∃x:A)[ φ(x) ]
Preciso achar um objeto do tipo A e demonstrar que meu objeto tem a propriedade φ.
Supondo que queremos afirmar que um certo objeto a : A é o objeto que procuramos:
Texto: «Vou demonstrar que φ(a).» Efeito: O alvo vira φ(a).
Lean: existsi a,
Se meu alvo é uma igualdade t = t.
Texto: «Imediato (pela reflexividade da =).»
Lean: refl,
Se meu alvo é uma igualdade s = t.
Precisamos calcular usando substituições no s até chegar no t ou vice versa.
Alternativamente podemos calcular começando no s para chegar até um objeto w, parar lá, pegar o t e calcular até chegar no mesmo objeto w.
Texto: «Calculamos: […cálculo aqui…]»
Lean: veja embaixo o como usar igualdades (para aplicá-las no alvo). Depois, veja como usar o calc que fica muito mais próximo no humano «Calculamos: […]»
Se meu alvo é uma negação ¬P
Então na verdade é uma implicação: P ⇒ ⊥ e logo já sabes o que fazer.
Se meu alvo é uma equivalência P ⇔ Q
Então na verdade é uma conjunção: (P ⇒ Q) & (Q ⇒ P) e logo já sabes o que fazer.
Se meu alvo já está nos meus dados
Lean: exact d, onde d é o rótulo do dado, ou apenas assumption, e Lean vai tentar achar teu alvo nos seus dados.
Para usar uma disjunção P ∨ Q
Texto: «Separamos em casos. Caso P: […]. Caso Q: […].»
Efeito: Dois novos “jogos” são criados onde todos os dados/alvos atuais são copiados e colados em cada um, só que no primeiro temos o P como dado extra, e no segundo temos o Q. Precisamos «fechar» ambos! Cuidado: cada joguinho tem seu próprio escopo, então mudanças/efeitos que linhas de demonstração têm nos dados/alvos executados no primeiro caso, não vão afetar o segundo.
Lean: cases hor, onde hor é o rotulo da disjunção que queremos usar.
Para dar rótulos às hipoteses de cada caso (por exemplo hp para o P e hq para o Q) use:
cases hor with hp hq,
Para usar uma conjunçào P ∧ Q
Text: Escrevendo «Obtenha o lado esqeurdo da P∧Q.» ganhamos o P nos nossos dados. Similarmente «Obtenha o lado direito da P∧Q.» nos dá o Q. Só que: ninguém merece escrever isso, então como humanos, tendo P∧Q nos nossos dados consideramos que já temos feito ámbas essas linhas acima e já temos ámbos os dados P e Q nos nossos dados!
Lean: cases h, onde h é o rótulo do P∧Q nos nossos dados.
Nesse exemplo o Lean vai nomear os dois novos dados (P e Q) por h_left : P e h_right : Q respectivamente.  Melhor dar seus próprios nomes, e fazemos isso com cases h with hp hq, assim teremos nos dados hp : P e hq : Q.
Cuidado: a palavra usada no Lean é confusa, pois não corresponde à palavra «casos» na lingua humana!
Para usar uma implicação P ⇒ Q
Podemos aplicá-la no P mas para fazer isso precisamos ter P nos nossos dados.
Texto: «Como P⇒Q e P, logo Q.» Efeito: ganhamos o Q nos dados.
Lean: have hq : Q := hpq hp, onde hq é o rótulo que eu escolhi para o dado que vou ganhar, e hpq é o rótulo do meu dado P→Q e hp o rótulo do meu P.
Text: Quando nosso alvo é Q e já temos P⇒Q nos nossos dados (mas ainda não o P para usá-lo e terminar), podemos dizer «Basta demonstrar o P (pois P⇒Q).» Efeito: o alvo muda de Q para P.
Lean: apply hpq, onde novamente hpq é o rótulo da implicação P→Q que temos nos dados.
Para usar uma negação ¬P
Novamente: a negação ¬P é a implicacão P⇒⊥. Então sabes como usar.
Para usar uma proposição universal (∀x:A)[ φ(x) ]
Basta aplicá-la em qualquer objeto a do tipo A e ela fornece o novo dado φ(a).
Texto: «Como a é um A, pela (fulana) temos φ(a).»
Lean: Tratamos uma proposição universal como se fosse uma função.  Tendo a : A e h : (∀x : A, P x) a aplicação do h no a (que denotamos por h a) é uma demonstração de P a, ou seja, da afirmação que o a tem a propriedade P.
Para usar uma proposição existencial (∃x:A)[ φ(x) ]
Podemos solicitar um a do tipo A que tem a propriedade φ:
Texto: «Seja a um A tal que φ(a).»
Lean: cases h with a ha, onde h é o rótulo do existencial, a o nome para o objeto que solicitamos e ha o rótulo do fato que nosso objeto a tem tal propriedade.
Cuidado: a palavra usada no Lean é confusa, pois não corresponde à palavra «casos» na lingua humana!
Para usar uma igualdade s = t ou uma equivalência P⇔Q
Texto: Substituimos objetos iguais por iguais citando a igualdade, e proposições equivalentes por equivalentes citando a equivalência.
Lean: usamos o rw heq onde heq é o nome da igualdade que queremos usar.
Obs: o Lean substitua de esquerda para a direita; para substituir na direção oposta use rw ← em vez de rw.
Obs: o Lean tenta usar a igualdade para substituir algo no alvo.  Se quiser aplicar tal substituição em algum dado rótulado por h, especifique adicionando um at h, assim: rw heq at h, onde novamente heq é o rótulo da igualdade que queremos usar e h é o rótulo da hipótese que queremos efetuar tal substituição.
Lean: usamos o rw para equivalências na mesma maneira.  Além disso, lembre-se que uma equivalência é apenas uma conjunção, então podemos usá-la nessa forma também.
Podemos juntar varios rw h₁, rw ←h₂, …, rw hₙ, consecutivos por rw [h₁, ←h₂, …, hₙ],
Usando dados on the fly
Observe que podemos usar dados para compor novos dados «on the fly»:
tendo f : A → B e a : A o f a denota a aplicação da implição f no dado a e logo é (demonstração de) B.  Assim, se nosso alvo no momento era B podemos escrever exact f a, para fechar.
A mesma coisa aplica para o resto dos conectivos, por exemplo se h : P∧Q entaõ h.left : P e h.right : Q.
Conversion mode
Se sentir vontade de caminhar nos teus dados e alvos e reescrever ou simplificar umas (sub)partes deles, veja o como usar o conv.  Não é necessário mas tem gente que não sobrevive sem conv.
Ex Falso Quodlibet
Também conhecido como: «explodi o mundo e logo meu alvo também morreu.»
Texto: «Eu vou achar uma contradição.»
Lean: exfalso,
Efeito: O alvo vira ⊥.
Talvéz já temos uma contradição óbvia dentro dos nossos dados. Para dizer isso pra o Lean e fechar a demonstração:
Lean: contradiction,
Indução
Texto: «Por indução no n.»
Lean: induction n with w hw, onde w é o nome do arbitrário natural da H.I. e hw o rótulo da H.I. mesmo.
Obs: se conseguir demonstrar sem usar a hipótese indutiva, significa que não era necessário usar indução.  Talvez sequer precisou tratar a base e a demonstração final do passo indutivo em formas diferentes!  Ou seja, atacando diretamente o ∀ teria dado certo.  Mas pode ser que precisou realmente tratar diferente o caso zero e o caso sucessor de alglém.  Isso fazemos com o cases n, onde n é o natural que queremos deparar nos casos n = O e n = Sn’ para algum natural n’.  Para escolher o nome usamos: cases n with n',.
Tips
Não esqueça terminar os tactics com ,.
Em vez de usar intro h, intro h', intro h'', etc., use intros h h' h'',.
Para repetir um tactic até não puder mais aplicá-lo use repeat { tactic }.
O processo inverso de intro é o revert: use revert h₁ … hₙ para tirar essas hipoteses dos dados e «devolvê-las» para a parte dos alvos.  Isso é bastante útil quando quisermos «fazer indução cedo, antes de “sejar” umas variáveis para carregar os ∀’s na nossa HI, a fortalecendo nesse jeito».  Mas para isso temos também o «especializado» induction n generalizing z₁ … zₙ onde z₁,…,zₙ são variáveis nos dados que queremos ganhá-las “com ∀” nas hipotéses indutivas.
Use injection quando quer «apagar os construtores numa igualdade no alvo, por exemplo um alvo Sn=Sm viraria n=m.  Tendo uma tal igualdade nos dados rotulada por h use injection h with h₁ … hₙ, para ganhar como novo dado as igualdades inferidas.  Neste exemplo, tendo o dado h : succ n = succ m, usando injection h with h', ganhamos o novo dado h' : n = m.
Se precisar dum dado P que não tens, mas tu consegue demonstrá-lo, use o have h : P, onde h o rótulo que tu quer escolher para dar esse dado.  Lean vai criar um novo joguinho com este alvo, e vai adicionar o h : P nos dados do joguinho original.  Ou seja: «aceito te dar o dado que tu queres ter, basta só demonstrá-lo.»
Feitiços não-construtivos
Primeiramente tente demonstrar os teoremas sem usar os seguintes “feitiços” não-construtivos. Considere que uma demonstração que precisou pelo menos um deles, pelo menos uma vez, é “manchada” com a mancha incomputacional de «não-construtiva». Qualquer demonstração de outro teorema que vai acabar usando esta, será considerada manchada também. Obs: continuaria uma demonstração correta.
⛤ LEM (Law of Excluded Middle)
Para qualquer proposição P que podemos imaginar, o LEM nos dá de presente o P∨¬P, que usamos (como disjunção) para separar nos casos P e ¬P.
Texto: «Separo em casos. Caso P: […]. Caso ¬P: […].»
Lean: by_cases h : P, onde P é a proposição que escolhemos e h o rótulo da hipótese correspondente para cada caso (P e ¬P aqui).
⛤ RAA (Reductio Ad Absurdum)
Tendo como alvo qualquer proposição P, supomos sua negação ¬P e tentamos achar uma contradição (⊥).
Texto: «Vamos supor que não P, e chegar num absurdo.»
Efeito: Ganhamos o ¬P nos dados; o alvo vira ⊥.
Lean: by_contradiction hboom, onde hboom é o rótulo que escolhemos para chamar o dado.  O Lean entende a abreviação by_contra para este tactic.
E depois?
Dominou tudo isto? Veja o [lean-theoremproving][Theorem Proving in Lean].