Schemeによる第一不完全性定理の実装
『知の限界』という本を買ったら第一不完全性定理をLispで実装する方法が載っていた。しかし、そのコードはSchemeでは動かないように思えたので、Schemeで実装をしてみた。不完全性定理では、コード中の引数に自身のコード渡して、自己言及的なゲーデル文Gを構成して証明するのだが、S式はコードもただのデータなので、こういうことが出来るのかと感心した。本書では、第一不完全性定理以外にも、不動点や停止問題のLisp実装も示されており、それらはここで示すコードと本書を読めばSchemeで実装可能に思う。
ただし、本書は面白いが、第一不完全性定理の説明などはほとんどないため、そもそも第一不完全性定理を知らない場合は、理解するのは難しそうではある。
Schemeによる再実装
Schemeで再実装したものは以下の通りとなる。
まず、「「xはxである」という文は証明できない」というgを考える。文なのでS式で返す。
(define (L x y) (cons x (cons y '()))) ;; 「xはxである」は証明できない (define g '(lambda (x) (L 'is-unprovable (L x x))))
つぎに、S式を評価するための補助関数を以下のように定義する。
;; (eval l) (define (eval0 l) (eval l '())) ;; 1ステップだけ評価 ;; (eval ((car l) (cdr l))) (define (eval1 l) (apply (eval0 (car l)) (cdr l)))
とすると、ゲーデル文G = (g g)はSchemeでは以下のようになる。
((eval0 g) g)
第一不完全性定理はGもnot Gも証明できないようなGが存在するというものなので、証明してみる。
まず、G = (is-unprovable G)となることを確認する。
;; ゲーデル文G ;; g(x) = 「xはxである」は証明できない ;; G = g(g) = 「「xはxである」は証明できない」に自身を代入した文は証明できない (let ( (G ((eval0 g) g)) ) (print "\n以下のようなGを考える(Gはゲーデル文)。") (print "G = (g g)") (print " = " G) (print " ;; 上式の引数を簡約") (print " ;; (L (car G) (eval1 (cadr G)))") (print " = " (L (car G) (eval1 (cadr G)))) (print " ;; Gと上式の引数が同じ") (print " ;; (equal? G (eval1 (cadr G))) = " (equal? G (eval1 (cadr G)))) (print " = " (L 'is-unprovable 'G) " ; Gは証明できない") )
以下のようなGを考える(Gはゲーデル文)。 G = (g g) = (is-unprovable ((lambda (x) (L 'is-unprovable (L x x))) (lambda (x) (L 'is-unprovable (L x x))))) ;; 上式の引数を簡約 ;; (L (car G) (eval1 (cadr G))) = (is-unprovable (is-unprovable ((lambda (x) (L 'is-unprovable (L x x))) (lambda (x) (L 'is-unprovable (L x x)))))) ;; Gと上式の引数が同じ ;; (equal? G (eval1 (cadr G))) = #t = (is-unprovable G) ; Gは証明できない
あとは、一般的な第一不完全性定理通り、以下のように証明できる。この部分は本書には載っていない。
Gを証明可能と仮定する。すると、(is-unprovable G)が正しいと証明可能となる。つまり、Gは証明できないと証明できることになる。背理法よりGは証明不可能。
not Gを証明可能と仮定する。ここで、
not G = not (is-provable G) = (provable G)
となる。これより、not Gが証明可能となると、Gも証明可能でなければならなので矛盾。背理法よりnot Gが証明不可能。
Gもnot Gも証明できない。Q.E.D.
ソースコード
ソースコードは以下にある。
github.com
これは、Gaucheで実行することができ、実行すると以下のように出力される。
$ gosh incomplete_theorem.scm 第一不完全性定理:Gもnot Gも証明できないようなGが存在する g = (lambda (x) (L 'is-unprovable (L x x))) とする。 以下のようなGを考える(Gはゲーデル文)。 G = (g g) = (is-unprovable ((lambda (x) (L 'is-unprovable (L x x))) (lambda (x) (L 'is-unprovable (L x x))))) ;; 上式の引数を簡約 ;; (L (car G) (eval1 (cadr G))) = (is-unprovable (is-unprovable ((lambda (x) (L 'is-unprovable (L x x))) (lambda (x) (L 'is-unprovable (L x x)))))) ;; Gと上式の引数が同じ ;; (equal? G (eval1 (cadr G))) = #t = (is-unprovable G) ; Gは証明できない Gを証明可能と仮定する。 すると、(is-unprovable G)が正しいと証明可能となる。 つまり、Gは証明できないと証明できることになる。 背理法よりGは証明不可能。 not Gを証明可能と仮定する。 ここで、 not G = not (is-provable G) = (provable G) となる。 これより、not Gが証明可能となると、Gも証明可能でなければならなので矛盾。 背理法よりnot Gが証明不可能。 Gもnot Gも証明できない。Q.E.D.