教会番号は、関数としての自然数のエンコードです。
(\ f x → (f x)) -- church number 1
(\ f x → (f (f (f x)))) -- church number 3
(\ f x → (f (f (f (f x))))) -- church number 4
きちんと、2つの教会の数を適用するだけで指数化できます。つまり、4対2を適用すると、教会番号16
、またはを取得します2^4
。明らかに、それは全く実用的ではありません。教会の数は線形のメモリ量を必要とし、本当に非常に遅いです。10^10
GHCIがすぐに正しく答えるようなものを計算すると、時間がかかり、とにかくコンピュータのメモリを合わせることができませんでした。
最近、最適なλエバリュエーターを使って実験しています。私のテストでは、最適なλ計算機に誤って次のように入力しました。
10 ^ 10 % 13
べき乗ではなく、乗法であると考えられていました。指を動かして、絶え間なく実行されているプログラムを絶望的に中止する前に、それは私の要求に答えました:
3
{ iterations: 11523, applications: 5748, used_memory: 27729 }
real 0m0.104s
user 0m0.086s
sys 0m0.019s
「バグアラート」が点滅しているので、Googleにアクセスして確認しました10^10%13 == 3
。しかし、λ計算機はその結果を見つけることを想定していなかったため、10 ^ 10をほとんど格納できません。私は科学についてそれを強調し始めました。それはすぐに私に答え20^20%13 == 3
、50^50%13 == 4
、60^60%3 == 0
。Haskell自体が(整数オーバーフローのために)計算できなかったため、外部ツールを使用してこれらの結果を検証する必要がありました(もちろん、IntsではなくIntegersを使用している場合です!)。それを限界まで押し上げ、これが次の答えでした200^200%31
。
5
{ iterations: 10351327, applications: 5175644, used_memory: 23754870 }
real 0m4.025s
user 0m3.686s
sys 0m0.341s
宇宙の原子ごとに宇宙のコピーが1つあり、合計で原子ごとにコンピューターがあった場合、教会番号を保存できませんでした200^200
。これにより、私のMacが本当にそれほど強力であるかどうかを尋ねるようになりました。おそらく、最適な評価者は、Haskellが遅延評価で行うのと同じ方法で、不要な分岐をスキップして答えにたどり着くことができたでしょう。これをテストするために、私はλプログラムをHaskellにコンパイルしました:
data Term = F !(Term -> Term) | N !Double
instance Show Term where {
show (N x) = "(N "++(if fromIntegral (floor x) == x then show (floor x) else show x)++")";
show (F _) = "(λ...)"}
infixl 0 #
(F f) # x = f x
churchNum = F(\(N n)->F(\f->F(\x->if n<=0 then x else (f#(churchNum#(N(n-1))#f#x)))))
expMod = (F(\v0->(F(\v1->(F(\v2->((((((churchNum # v2) # (F(\v3->(F(\v4->(v3 # (F(\v5->((v4 # (F(\v6->(F(\v7->(v6 # ((v5 # v6) # v7))))))) # v5))))))))) # (F(\v3->(v3 # (F(\v4->(F(\v5->v5)))))))) # (F(\v3->((((churchNum # v1) # (churchNum # v0)) # ((((churchNum # v2) # (F(\v4->(F(\v5->(F(\v6->(v4 # (F(\v7->((v5 # v7) # v6))))))))))) # (F(\v4->v4))) # (F(\v4->(F(\v5->(v5 # v4))))))) # ((((churchNum # v2) # (F(\v4->(F(\v5->v4))))) # (F(\v4->v4))) # (F(\v4->v4))))))) # (F(\v3->(((F(\(N x)->F(\(N y)->N(x+y)))) # v3) # (N 1))))) # (N 0))))))))
main = print $ (expMod # N 5 # N 5 # N 4)
これは正しく1
(5 ^ 5 % 4
)を出力しますが、上に何かを投げる10^10
とスタックし、仮説を排除します。
私が使用し、最適な評価は、指数関数的モジュラス数学の任意の並べ替えが含まれていませんでした長い160ライン、最適化されていないJavaScriptプログラムである-と私は同じように簡単だった使用ラムダ計算モジュラス機能:
(λab.(b(λcd.(c(λe.(d(λfg.(f(efg)))e))))(λc.(c(λde.e)))(λc.(a(b(λdef.(d(λg.(egf))))(λd.d)(λde.(ed)))(b(λde.d)(λd.d)(λd.d))))))
特定のモジュラー算術アルゴリズムや公式は使用していません。では、最適な評価者はどのようにして正しい答えを得ることができるのでしょうか?
node test.js
。ご不明な点がありましたらお知らせください。