教堂数字是自然数作为函数的编码。
(\ 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
整整齐齐地,您只需应用两个教堂数字即可对其求幂。也就是说,如果您将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本身无法计算(由于整数溢出)(当然,这是使用Integers而不是Ints的结果!)。将其推到极限,这是对以下问题的答案200^200%31
:
5
{ iterations: 10351327, applications: 5175644, used_memory: 23754870 }
real 0m4.025s
user 0m3.686s
sys 0m0.341s
如果我们对宇宙中的每个原子都有一个宇宙的副本,并且对于总共拥有的每个原子我们都拥有一台计算机,那么我们将无法存储教堂编号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程序,其中不包含任何指数模数数学-而且我使用的lambda-calculus模数函数同样简单:
(λ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
。如果您有任何问题,请告诉我。