SICP問題2.6
Church数(Church numerals)の問題。
0と1を足す演算の定義
(define zero (lambda (f) (lambda (x) x))) (define (add-1 n) (lambda (f) (lambda (x) (f ((n f) x)))))
ためしに実行してみる。
(add-1 zero) ; #<closure (add-1 add-1)> (zero add-1) ; #<closure (zero zero)>
ん? 良く分からんので、ためしに guile でも動かしてみる
(add-1 zero) ; #<procedure #f (x)> (zero add-1) ; #<procedure #f (f)>
うーん。ますます良く分からないのでChurch数をネットで調べてみると
要は、ある数は、ある関数fを何回xに適用するか、という定義にしてしまうのである。
404 Blog Not Found:TuringとChurchの狭間で
しかし、ここでの特徴は、「普通の数値に戻す」ことではなくて、「関数をそのまま数として扱う」ということにある。
404 Blog Not Found:TuringとChurchの狭間で
ということらしい。
ここで先ほどの zero について考えてみると
(lambda (f) (lambda (x) x)) ; => (lambda (f) (lambda (x) x)) ; => (lambda (x) x) ; => (x)
と f を一回も適用していない x を返すので、ゼロだということらしい。
次に (add-1 zero) してみる。(add-1 n) は
(lambda (f) (lambda (x) (f ((n f) x))))
なので
(add-1 zero) ; => ((lambda (f) (lambda (x) (f ((n f) x)))) zero) ; => (lambda (f) (lambda (x) (f ((zero f) x)))) ; => (lambda (f) (lambda (x) (f ((lambda (x) x) x)))) ; => (lambda (f) (lambda (x) (f x))) ; => (lambda (f) (f x)) ; => (f x)
ということで x に f を一回適用したので one になる。
以上のことから one の定義は以下のようになる
(define one (lambda (f) (lambda (x) (f x))))
ということで確認してみる。(そもそも zero も add-1 もちゃんと確かめられていないし)
確認のために以下のような inc を定義する
(define (inc n) (+ n 1)) (define (church-to-int c) ((c inc) 0))
確認。
(church-to-int zero) ; 0 (church-to-int one) ; 1 (church-to-int (add-1 zero)) ; 1 (church-to-int (add-1 one)) ; 2
次は two の定義。f を x に適用した回数だからは以下のようになる
(define two (lambda (f) (lambda (x) (f (f x)))))
確認。
(church-to-int two) ; 2 (church-to-int (add-1 two)) ; 3
ヨサゲ。次は加算手続き。
加算は one + two だと (f x) + (f (f x)) = (f (f (f x))) という感じになればよいはず。
ちなみにλ記法では
zero = λfx.x one = λfx.fx two = λfx.ffx three = λfx.fffx
となるので、上記の式は
λfx.fx + λfx.ffx = λfx.fffx
となる。以下が実装。
(define (church+ m n) (lambda (f) (lambda (x) ((m f) ((n f) x)))))
ということでカンニングしながらなんとか完成。
(church-to-int (church+ one two)) ; 3 (church-to-int (church+ one zero)) ; 1 (church-to-int (church+ zero one)) ; 1 (church-to-int (church+ zero two)) ; 2 (church-to-int (church+ two two)) ; 4
ついでにテスト用に three, four も定義
(define three (lambda (f) (lambda (x) (f (f (f x)))))) (define four (lambda (f) (lambda (x) (f (f (f (f x)))))))