Kilise sayıları doğal sayıların fonksiyon olarak kodlanmasıdır.
(\ 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
Düzgünce, sadece uygulayarak 2 kilise sayısını üs alabilirsiniz. Yani, 4 ila 2 uygularsanız, kilise numarasını alırsınız 16
veya 2^4
. Açıkçası, bu tamamen pratik değildir. Kilise sayılarının doğrusal bir hafızaya ihtiyacı vardır ve gerçekten çok yavaştır. 10^10
GHCI'nin hızlı bir şekilde doğru cevapladığı gibi bir şey hesaplamak uzun zaman alır ve yine de bilgisayarınızdaki belleği sığdıramaz.
Son zamanlarda optimal λ değerlendiricileri ile deneyler yapıyorum. Testlerimde, optimum λ-hesap makineme yanlışlıkla aşağıdakileri yazdım:
10 ^ 10 % 13
Üstel değil çarpma olması gerekiyordu. Çaresizce sonsuza dek çalışan programı iptal etmek için parmaklarımı hareket ettirmeden önce, isteğimi yanıtladı:
3
{ iterations: 11523, applications: 5748, used_memory: 27729 }
real 0m0.104s
user 0m0.086s
sys 0m0.019s
Benim "hata uyarısı" yanıp sönerken, Google'a gittim ve 10^10%13 == 3
gerçekten doğruladım . Ancak λ-hesaplayıcının bu sonucu bulması beklenmiyordu, 10 ^ 10'u zar zor saklayabiliyordu. Bilim için vurgulamaya başladım. Bu beni anında cevap 20^20%13 == 3
, 50^50%13 == 4
, 60^60%3 == 0
. Haskell'in kendisi (tamsayı taşması nedeniyle) hesaplayamadığı için bu sonuçları doğrulamak için harici araçlar kullanmak zorunda kaldım (elbette Ingers değil Ingers kullanıyorsan!). Sınırlarını zorlayan, bunun cevabı şuydu :200^200%31
5
{ iterations: 10351327, applications: 5175644, used_memory: 23754870 }
real 0m4.025s
user 0m3.686s
sys 0m0.341s
Evrendeki her atom için evrenin bir kopyasına sahip olsaydık ve toplamda sahip olduğumuz her atom için bir bilgisayarımız olsaydı, kilise numarasını saklayamazdık 200^200
. Bu, mac'umun gerçekten güçlü olup olmadığını sorgulamamı sağladı. Belki de optimal değerlendirici, gereksiz dalları atlayıp Haskell'in tembel değerlendirmeyle aynı şekilde cevabına varmayı başardı. Bunu test etmek için λ programını Haskell'e derledim:
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)
Bu doğru çıktı 1
( 5 ^ 5 % 4
) - ama yukarıda herhangi bir şey atmak 10^10
ve sıkışmış olacak, hipotezi ortadan kaldıracak.
Kullandığım optimal değerlendirici , herhangi bir üstel modül matematiği içermeyen 160 satır uzunluğunda, optimize edilmemiş bir JavaScript programı - ve kullandığım lambda-calculus modülüs işlevi de aynı derecede basitti:
(λ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))))))
Spesifik modüler aritmetik algoritma veya formül kullanmadım. Peki, optimal değerlendirici doğru cevaplara nasıl ulaşabilir?
node test.js
. Herhangi bir sorunuz varsa bize bildirin.