tpl-in-lean

§1.3 타당성과 추론🔗

x > 0의 참·거짓은 상태에 달려 있다. x가 3이면 참이고 -1이면 거짓이다. 단언 하나만으로는 진리값이 없고 상태가 있어야 정해진다는 것이 §1.2의 결론이었다.

그런데 상태를 하나 고르지 않고 전부 훑으면 단언 자체의 성질이 나온다. x > 0 ∨ x ≤ 0은 어떤 상태에서도 참이고, x > 0 ∧ x ≤ 0은 어떤 상태에서도 거짓이다. Reynolds는 §1.3에서 그런 성질 넷에 이름을 붙인다.

/-- **타당(valid)** — 모든 상태에서 참. Reynolds §1.3. -/ def Valid (p : Assert V) : Prop := ∀ σ : State V, ⟦p⟧ₐ σ /-- **충족 불가능(unsatisfiable)** — 어떤 상태에서도 거짓. -/ def Unsat (p : Assert V) : Prop := ∀ σ : State V, ¬ ⟦p⟧ₐ σ /-- `p`가 `q`보다 **강하다(stronger)**. `q`는 `p`보다 **약하다(weaker)**. Reynolds가 곧바로 붙이는 단서가 있다. > *"'stronger' and 'weaker' are dual preorders, which does not quite jibe with normal > English usage. For example, any assertion is both stronger and weaker than itself."* `Stronger`는 반사적이고 추이적인 준순서(preorder)다. 어떤 단언이든 자기 자신보다 강하면서 동시에 약한 것은 반사성 때문이다. 의미가 같지만 구문이 다른 단언도 서로 강하므로, 구문 등식에 대한 반대칭성은 일반적으로 성립하지 않는다. -/ def Stronger (p q : Assert V) : Prop := ∀ σ : State V, ⟦p⟧ₐ σ → ⟦q⟧ₐ σ /-- **동치(equivalent)** — 같은 뜻. -/ def Equivalent (p q : Assert V) : Prop := ∀ σ : State V, (⟦p⟧ₐ σ ↔ ⟦q⟧ₐ σ)

여기까지는 전부 뜻으로 정의했다. 상태를 훑어 보고 판정한다.

증명은 그렇게 하지 않는다. 공리에서 출발해 규칙을 적용해 가며 문장을 얻고, 그 과정에서 상태를 한 번도 보지 않는다. 그것을 따로 정의한다.

/-- 술어 논리의 작은 추론 체계. Reynolds §1.3 p.13이 공리·공리꼴·두 전제 규칙·한 전제 규칙의 예로 직접 드는 넷 그대로다: `x + 0 = x`, `e₁ = e₀ ⇒ e₀ = e₁`, 전건 긍정, 보편 일반화. 완전한 체계가 아니고 그럴 의도도 없다. 책도 이 넷을 "예시"라고만 하고 나머지는 논리학 교과서로 미룬다(모듈 docstring의 "책과의 차이" 참고). -/ inductive Proof : Assert V → Prop where /-- 공리: `x + 0 = x`. 책은 메타변수가 없는 구체적인 객체 변수 x로 든다 — 바로 다음 공리꼴과 대조하려는 것이다(p.13, "notice the special role of axiom schemas"). **책과의 차이**: 여기서는 모든 객체 변수 x에 대해 한 번에 선언한다. Lean에서 변수마다 따로 공리를 선언하면 쓸 수 없는 정의가 되기 때문이다. 책의 "메타변수 없음"은 이 x 하나를 구체적으로 고정했을 때의 이야기이고, 다형화 자체는 책에 없는 저장소의 선택이다. -/ | addZero (x : V) : Proof (.cmp .eq (.bin .add (.var x) (.num 0)) (.var x)) /-- 공리꼴: `e₁ = e₀ ⇒ e₀ = e₁`. 전제 없이 바로 쓸 수 있지만 `e₀`, `e₁`이 메타변수라서 임의의 정수 식 쌍에 대한 사례를 전부 대신한다 — 공리와 공리꼴의 차이가 바로 이 메타변수 유무다(p.13, "their instances are assertions that can appear anywhere in a proof, regardless of what, if anything, precedes them"). -/ | eqSymmSchema (e₀ e₁ : IntExp V) : Proof (.bin .imp (.cmp .eq e₁ e₀) (.cmp .eq e₀ e₁)) /-- 두 전제 규칙 — 전건 긍정(modus ponens). -/ | mp {p q : Assert V} : Proof p → Proof (.bin .imp p q) → Proof q /-- 한 전제 규칙 — 보편 일반화(∀-도입). 전제가 타당할 때만 결론이 타당해진다. 이 파일 §4에서 이 규칙과 함의 `p ⇒ ∀v. p`를 나란히 놓고 비교한다. -/ | genAll (v : V) {p : Assert V} : Proof p → Proof (.quant .all v p)

Proof p는 "p를 이 규칙들로 유도할 수 있다"는 뜻이다. Valid p와 달리 상태가 어디에도 나오지 않는 것을 확인해 보라. 두 정의는 서로를 모른다.

규칙으로 얻은 것이 실제로 참임을 보장하는 성질이 건전성(soundness)이다. Validity.lean에서 Proof p → Valid p로 증명한다. 증명은 Proof에 대한 귀납법이다 — 규칙 하나하나가 타당성을 보존하는지 확인하면 된다.

반대 방향(Valid p → Proof p, 완전성)은 성립하지 않는다. 아래 곁가지에서 다룬다.

규칙과 함의는 다른 것이다🔗

보편 일반화 규칙은 건전한데, 같은 재료로 만든 함의는 타당하지 않다. 둘이 같은 말을 하는 것처럼 보여서 §1.3에서 가장 자주 걸리는 곳이다. 두 정리를 나란히 놓는다.

/-- 규칙 쪽. `p`가 타당하면 `∀v. p`도 타당하다. -/ @[exercise "§1.3 gen-sound" 1] theorem valid_forall_of_valid (v : V) {p : Assert V} (h : Valid p) : Valid (.quant .all v p)/-- 함의 쪽. `x > 0 ⇒ ∀x. x > 0`은 타당하지 않다. Reynolds의 반례를 그대로 쓴다. `x ↦ 3` 인 상태에서 왼쪽은 참이고, 오른쪽은 `x`에 0 을 넣으면 거짓이다. 같은 재료로 만든 규칙(위)과 함의(여기)의 판정이 갈린다. -/ @[exercise "§1.3 gen-not-imp" 2] theorem not_valid_imp_forall : ¬ Valid (.bin .imp (.cmp .gt (.var "x") (.num 0)) (.quant .all "x" (.cmp .gt (.var "x") (.num 0))) : Assert String)

규칙은 전제가 타당할 때 결론이 타당하다고 말한다. 함의는 한 상태 안에서 왼쪽이 참이면 오른쪽도 참이라고 말한다. x ↦ 3 인 상태 하나만 잡으면 뒤쪽이 무너진다.

곁가지 — 완전성과 괴델🔗

Reynolds는 §1.3을 닫으면서 이 책이 다루지 않을 것을 알려 준다. 코드로 옮기지 않기로 한 논의라 여기에 산문으로 남긴다.

건전성의 역이 완전성(completeness)이다. 타당한 것은 모두 유도되는가.

답은 "타당"을 어떻게 정의했느냐에 달렸다.

  • 우리처럼 정수에 대한 표준 해석을 고정하면 참인 산술 문장까지 모두 다뤄야 한다. 산술을 충분히 표현하면서 공리와 증명을 기계적으로 열거·검사할 수 있는 일관된 체계는 그 참인 문장을 전부 증명할 수 없다. 괴델의 불완전성 정리는 이런 조건 아래에서 적용된다.

  • 논리적 타당성(logical validity) — 연산 기호의 뜻까지 임의로 바꿔도 성립하는 것 — 으로 정의하면 일차 논리에는 건전하고 완전한 효과적 증명 체계가 있다. 괴델의 완전성 정리가 그것이다.

같은 이름의 두 정리가 반대 방향을 말하는 것처럼 보이지만, 두 "타당"이 다른 것이다.

Reynolds는 여기에 실용적인 단서를 붙인다. 프로그램 검증에서 논리적 완전성은 별 쓸모가 없다는 것이다. 우리는 +가 정말 덧셈인 해석에만 관심이 있기 때문이다. 그 예외는 §3.8에서 다룬다.

왜 코드로 만들지 않았나. 이 주제를 형식화하려면 증명론 전체가 따라온다 — 산술의 인코딩, 증명 가능성 술어, 대각화. Reynolds 본인이 다루지 않고, 1장의 목표와도 멀다. Lean으로 괴델을 보고 싶다면 mathlib 밖의 별도 프로젝트를 찾는 편이 낫다.