キューキー符号化で前駆関数を構築する
4759 ワード
目次
引用する
王垠は博文「GTF-Great Teacher Friedman」で、コネル大学の同級生が1週間かけて前駆関数を考え出したチャーチ符号化について、クリンニの最初の設計とは全く異なると述べた.
ウィキペディアのチャーチコードのフレーズには、この2つの方法が紹介されています.
ゆえにλ演算は「無状態」であり,前駆関数を構築するのは確かに簡単ではない.
1つの方法(クリンニが最初に構築したものかもしれない)は、まず秩序対を構築し、秩序対によって2つの隣接する数を保存することによって、前駆関数を実現する.この方法は理解しやすく、チャーチ符号化を話す多くの本が話せる方法でもある.
王垠のこの同級生が考えている方法は分かりにくい.概念的には,丘奇数を特殊な構造Valueにカプセル化し,丘奇数に対するシフトを実現した後,(Value→Value)型の後継関数を再構築することである.公理「ある数の後が自然数0に対応するValue」により,「-1」のValue表現を構築し,前駆関数の構築に成功した.
ガイド人
以下では、パラメータとして1つの丘奇数を受け入れ、パラメータの前駆丘奇数を返す前駆関数をPRED
と統一して記す.PRED
の概略フレームワークは(define PRED
(lambda (number)
(lambda (f x)
...)))
なお、(PRED ZERO)
の値は、依然として奇数丘0 ZERO
である.
秩序を立てて前駆関数を構築する方法は余計なことではありませんが、ここではウィキペディアで与えられた構造構想、つまり王垠が言った彼の同級生が与えた方法について具体的に話します.
まずは丘奇数の構造を振り返ってみます.丘奇数の構造構想は,関数ネスト層数で自然数を表現することである.この考え方によれば、丘奇数は、2つのパラメータを受け入れる.1つは、ネスト呼び出しを繰り返すための関数f
であり、2つは、この関数に伝達されるパラメータx
である.(define ZERO
(lambda (f x) x))
(define ONE
(lambda (f x) (f x)))
(define TWO
(lambda (f x) (f (f x))))
後続関数SUCC
は、既存の丘奇数に基づいてf
を1層多くネストし、新しい丘奇数に戻ると容易に構築できる.(define SUCC
(lambda (number)
(lambda (f x)
(f (number f x)))))
複数のネストは簡単ですが、1つのネストを外すのは面倒です.PRED
を構築する鍵は、「再定義」キュー奇数および後続関数にある.パッケージ化の手段により、VALUE
と記載された丘奇数の容器を構築することができる.これは、入力されたキュー奇数をパラメータの位置に保存する閉パケット(の戻り値、すなわちネストされた呼び出し部(f..(f x)..)
、簡潔化のため、以下同様)を受け入れ、(define VALUE
(lambda (number)
(lambda (package)
(package number))))
わかりやすく、((VALUE n) f) = (f n) ( (*))
この性質を利用して、パッケージ化されたVALUEからEXTRACT
を得るための補助関数number
を構築することができる.(define EXTRACT
(lambda (value)
(value (lambda (x) x))))
上の性質は後続関数の挙動に非常に近い.この性質に基づいて、新しい後継関数INC
を構築することができ、丘奇数後継関数とは異なり、INC
はパッケージ化されたVALUEを入力とし、その後のVALUEを出力とする.;; VALUE -> VALUE
(define INC
(lambda (value)
(lambda (package)
(package (value f)))))
(value f)
は元の丘奇数の後継数(丘奇数でもある)を得るため、INC
はそれをVALUEに再カプセル化する必要がある.なお、INC
は自由変数f
を導入しているが、このf
はPRED
のフレームワーク(すなわち、丘奇数に必要なf
)にすでに現れているので、実際には制約されている.
次のステップでは、INC
の繰返し特性を検証し、"-1"に対応するVALUEを構築し、これを反復開始点とする.
表記V0 = (VALUE x)
は、性質(*)およびINC
によって定義される. V0 = (VALUE x)
(INC V0) = (VALUE (f x)) = V1
(INC (INC V0)) = (VALUE (f (f x))) = V2
...
(INC Vn) = V[n+1]
INC
をV0
でn
回繰り返し呼び出すと(n
は丘奇数)、(n INC V0) = Vn
ここでVn
は、自然数nに対応するVALUEとして理解される.前駆関数を構築するには、V[-1]
ではなくV[-1]
からこの反復プロセスを開始する「−1」、すなわちV0
を再構築するだけで、前駆関数を実現することができる.
明らかに、V[-1]
は性質を有しなければならない.(INC V[-1]) = (VALUE x) = V0
展開(lambda (package) (package (V[-1] f))) = (lambda (package) (package x))
これにより得られる(合一)、(V[-1] f) = x
適用η-変換可能V[-1] = (lambda (u) x)
V[-1]
およびV0
を観察すると、V[-1]
は実際には丘奇数の0に対応し、V0
は丘奇数の1に対応することが分かった.つまり、**はVALUE
のカプセル化により、丘奇数を"左シフト"する目的を達成し、丘奇数の"-1"から反復させ、丘奇数で結果を返し、前駆の効果を実現する.**次のようになります.(n INC V[-1]) = V[n-1]
得られたVALUEに対応するキュー奇数ネスト形式をEXTRACT
を用いて抽出し,PRED
関数の関数体を得た.なお、(EXTRACT V[-1]) = x
であるため、(PRED ZERO) = ZERO
は満足である.
最後に、前の構成のVALUE
(補助関数、実際には必要ありません)、EXTRACT
、INC
を組み合わせて、PRED
関数を得ることができます.(define TEN
(lambda (f x) (f (f (f (f (f (f (f (f (f (f x))))))))))))
(define PRED
(lambda (number)
(lambda (f x)
(define EXTRACT
(lambda (value)
(value (lambda (x) x))))
(define INC
(lambda (value)
(lambda (package)
(package (value f)))))
(define V-1
(lambda (u) x))
(EXTRACT (number INC V-1)))))
((PRED TEN)
(lambda (x) (+ x 1))
0)
以下に簡略化:(define PRED
(lambda (number)
(lambda (f x)
((number
(lambda (value)
(lambda (package)
(package (value f))))
(lambda (u) x))
(lambda (x) x)))))
これが最終的に得られた前駆関数である.
参考資料
以下では、パラメータとして1つの丘奇数を受け入れ、パラメータの前駆丘奇数を返す前駆関数を
PRED
と統一して記す.PRED
の概略フレームワークは(define PRED
(lambda (number)
(lambda (f x)
...)))
なお、
(PRED ZERO)
の値は、依然として奇数丘0 ZERO
である.秩序を立てて前駆関数を構築する方法は余計なことではありませんが、ここではウィキペディアで与えられた構造構想、つまり王垠が言った彼の同級生が与えた方法について具体的に話します.
まずは丘奇数の構造を振り返ってみます.丘奇数の構造構想は,関数ネスト層数で自然数を表現することである.この考え方によれば、丘奇数は、2つのパラメータを受け入れる.1つは、ネスト呼び出しを繰り返すための関数
f
であり、2つは、この関数に伝達されるパラメータx
である.(define ZERO
(lambda (f x) x))
(define ONE
(lambda (f x) (f x)))
(define TWO
(lambda (f x) (f (f x))))
後続関数
SUCC
は、既存の丘奇数に基づいてf
を1層多くネストし、新しい丘奇数に戻ると容易に構築できる.(define SUCC
(lambda (number)
(lambda (f x)
(f (number f x)))))
複数のネストは簡単ですが、1つのネストを外すのは面倒です.
PRED
を構築する鍵は、「再定義」キュー奇数および後続関数にある.パッケージ化の手段により、VALUE
と記載された丘奇数の容器を構築することができる.これは、入力されたキュー奇数をパラメータの位置に保存する閉パケット(の戻り値、すなわちネストされた呼び出し部(f..(f x)..)
、簡潔化のため、以下同様)を受け入れ、(define VALUE
(lambda (number)
(lambda (package)
(package number))))
わかりやすく、
((VALUE n) f) = (f n) ( (*))
この性質を利用して、パッケージ化されたVALUEから
EXTRACT
を得るための補助関数number
を構築することができる.(define EXTRACT
(lambda (value)
(value (lambda (x) x))))
上の性質は後続関数の挙動に非常に近い.この性質に基づいて、新しい後継関数
INC
を構築することができ、丘奇数後継関数とは異なり、INC
はパッケージ化されたVALUEを入力とし、その後のVALUEを出力とする.;; VALUE -> VALUE
(define INC
(lambda (value)
(lambda (package)
(package (value f)))))
(value f)
は元の丘奇数の後継数(丘奇数でもある)を得るため、INC
はそれをVALUEに再カプセル化する必要がある.なお、INC
は自由変数f
を導入しているが、このf
はPRED
のフレームワーク(すなわち、丘奇数に必要なf
)にすでに現れているので、実際には制約されている.次のステップでは、
INC
の繰返し特性を検証し、"-1"に対応するVALUEを構築し、これを反復開始点とする.表記
V0 = (VALUE x)
は、性質(*)およびINC
によって定義される. V0 = (VALUE x)
(INC V0) = (VALUE (f x)) = V1
(INC (INC V0)) = (VALUE (f (f x))) = V2
...
(INC Vn) = V[n+1]
INC
をV0
でn
回繰り返し呼び出すと(n
は丘奇数)、(n INC V0) = Vn
ここで
Vn
は、自然数nに対応するVALUEとして理解される.前駆関数を構築するには、V[-1]
ではなくV[-1]
からこの反復プロセスを開始する「−1」、すなわちV0
を再構築するだけで、前駆関数を実現することができる.明らかに、
V[-1]
は性質を有しなければならない.(INC V[-1]) = (VALUE x) = V0
展開
(lambda (package) (package (V[-1] f))) = (lambda (package) (package x))
これにより得られる(合一)、
(V[-1] f) = x
適用η-変換可能
V[-1] = (lambda (u) x)
V[-1]
およびV0
を観察すると、V[-1]
は実際には丘奇数の0に対応し、V0
は丘奇数の1に対応することが分かった.つまり、**はVALUE
のカプセル化により、丘奇数を"左シフト"する目的を達成し、丘奇数の"-1"から反復させ、丘奇数で結果を返し、前駆の効果を実現する.**次のようになります.(n INC V[-1]) = V[n-1]
得られたVALUEに対応するキュー奇数ネスト形式を
EXTRACT
を用いて抽出し,PRED
関数の関数体を得た.なお、(EXTRACT V[-1]) = x
であるため、(PRED ZERO) = ZERO
は満足である.最後に、前の構成の
VALUE
(補助関数、実際には必要ありません)、EXTRACT
、INC
を組み合わせて、PRED
関数を得ることができます.(define TEN
(lambda (f x) (f (f (f (f (f (f (f (f (f (f x))))))))))))
(define PRED
(lambda (number)
(lambda (f x)
(define EXTRACT
(lambda (value)
(value (lambda (x) x))))
(define INC
(lambda (value)
(lambda (package)
(package (value f)))))
(define V-1
(lambda (u) x))
(EXTRACT (number INC V-1)))))
((PRED TEN)
(lambda (x) (+ x 1))
0)
以下に簡略化:
(define PRED
(lambda (number)
(lambda (f x)
((number
(lambda (value)
(lambda (package)
(package (value f))))
(lambda (u) x))
(lambda (x) x)))))
これが最終的に得られた前駆関数である.