Церковні числа - це кодування натуральних чисел як функцій.
(\ 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
Коли миготіло повідомлення про помилку, я 10^10%13 == 3
дійсно перейшов до Google і перевірив . Але λ-калькулятор не повинен був знайти цього результату, він ледве може зберігати 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
. Це змусило мене запитати, чи справді мій мак такий сильний. Можливо, оптимальний оцінювач зміг пропустити непотрібні гілки і прийти прямо до відповіді так само, як і 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
. Повідомте мене, якщо у вас є питання.