Anonim rekursiya - Anonymous recursion

Yilda Kompyuter fanlari, anonim rekursiya bu rekursiya bu aniq funktsiyani nomiga chaqirmaydi. Buni aniq yoki a yordamida amalga oshirish mumkin yuqori darajadagi funktsiya - funktsiyani argument sifatida o'tkazish va uni chaqirish - yoki bilvosita, orqali aks ettirish mavjud kontekstga qarab ma'lum funktsiyalarga, xususan "joriy funktsiya" yoki ba'zan "joriy funktsiyani chaqirish funktsiyasi" ga kirishga imkon beradigan xususiyatlar.

Dasturlash amaliyotida noma'lum rekursiya ayniqsa ishlatiladi JavaScript, uni qo'llab-quvvatlash uchun aks ettirish imkoniyatlarini taqdim etadi. Umumiy dasturlash amaliyotida bu yomon uslub deb hisoblanadi va uning o'rniga nomlangan funktsiyalar bilan rekursiya taklif etiladi. Argumentlar sifatida aniq o'tish funktsiyalari orqali anonim rekursiya, funktsiyalarni argument sifatida qo'llab-quvvatlaydigan har qanday tilda mumkin, ammo bu amalda kamdan-kam qo'llaniladi, chunki bu nom bilan aniq takrorlanishga qaraganda uzoqroq va kamroq.

Nazariy kompyuter fanida noma'lum rekursiya muhim ahamiyatga ega, chunki u rekursiyani nomlangan funktsiyalarni talab qilmasdan amalga oshirishi mumkin. Bu ayniqsa muhimdir lambda hisobi, noma'lum unary funktsiyalariga ega, ammo har qanday rekursiv funktsiyani hisoblashga qodir. Ushbu noma'lum rekursiya orqali umumiy tarzda ishlab chiqarilishi mumkin sobit nuqtali kombinatorlar.

Foydalanish

Anonim rekursiya, avvalambor, rekursiyaga imkon berish uchun ishlatiladi noma'lum funktsiyalar, ayniqsa ular shakllanganda yopilish yoki sifatida ishlatiladi qo'ng'iroqlar, majbur bo'lmaslik uchun ismni bog'lash funktsiyasi.

Anonim rekursiya, avvalambor, "joriy funktsiya" ni chaqirishdan iborat to'g'ridan-to'g'ri rekursiya. Anonim bilvosita rekursiya masalan, "qo'ng'iroq qiluvchini (oldingi funktsiyani)" qo'ng'iroq qilish yoki kamdan-kam hollarda yuqoriga ko'tarish orqali mumkin chaqiruv to'plami va bu ishlab chiqarish uchun zanjirband qilinishi mumkin o'zaro rekursiya. The o'z-o'ziga murojaat qilish ning "joriy funktsiyasi" ning funktsional ekvivalentibu "kalit so'z ob'ektga yo'naltirilgan dasturlash, hozirgi kontekstga murojaat qilishga imkon beradi.

Anonim rekursiya, shuningdek, nomlangan funktsiyalar uchun ishlatilishi mumkin, aksincha ularni nomlari bilan chaqirish, joriy funktsiya bo'yicha takrorlanayotganligini ko'rsatish yoki funktsiyani nomini o'zgartirishga hojat qoldirmasdan, nomini o'zgartirishga imkon berish. Biroq, masala bo'yicha dasturlash uslubi bu umuman qilinmaydi.

Shu bilan bir qatorda

Nomlangan funktsiyalar

Odatiy alternativa - nomlangan funktsiyalar va nomlangan rekursiyadan foydalanish. Noma'lum funktsiyani hisobga olgan holda, buni JavaScript-dagi nomlangan funktsiya ifodalarida bo'lgani kabi funktsiyaga ismni bog'lash orqali yoki funktsiyani o'zgaruvchiga tayinlash va keyin JavaScript-dagi funktsiyalar bayonotidagi kabi o'zgaruvchini chaqirish orqali amalga oshirish mumkin. Noma'lum funktsiyalarga ruxsat beruvchi tillar odatda ushbu funktsiyalarni o'zgaruvchiga berishga imkon beradiganligi sababli (agar birinchi darajali funktsiyalar bo'lmasa), ko'p tillar funktsiyaga murojaat qilish usulini taqdim etmaydi va noma'lum rekursiyani aniq rad etadi; misollar kiradi Boring.[1]

Masalan, JavaScript-da faktorial funktsiyani anonim rekursiya orqali aniqlash mumkin:[2]

[1, 2, 3, 4, 5].xarita(funktsiya(n) {     qaytish (!(n > 1)) ? 1 : dalillar.kalli(n-1) * n;});

Nomlangan funktsiya ifodasini ishlatish uchun qayta yozilgan:

[1, 2, 3, 4, 5].xarita(funktsiya faktorial(n) {     qaytish (!(n > 1)) ? 1 : faktorial(n-1) * n;});

Funktsiyalarni argument sifatida o'tkazish

Amaldagi funktsiya yoki chaqirish funktsiyasiga murojaat qilish mexanizmisiz ham, argument sifatida funktsiyalarga ruxsat beradigan tilda anonim rekursiya mumkin. Bu asosiy rekursiv funktsiyaga yana bir parametr qo'shish va ushbu parametrni rekursiv chaqiriq uchun funktsiya sifatida ishlatish orqali amalga oshiriladi. Bu yuqori darajadagi funktsiyani yaratadi va ushbu yuqori funktsiyani uzatadi o'zi haqiqiy rekursiv funktsiya doirasida noma'lum rekursiyaga imkon beradi. Buni faqat anonim tarzda qo'llash orqali amalga oshirish mumkin sobit nuqtali kombinator ushbu yuqori darajadagi funktsiyaga. Bu asosan akademik qiziqish uyg'otadi, xususan lambda hisobining rekursiyaga ega ekanligini ko'rsatish uchun, natijada olingan ifoda asl nomlangan rekursiv funktsiyadan ancha murakkabroq. Aksincha, sobit uchli kombinatorlardan foydalanishni umumiy ravishda "anonim rekursiya" deb atash mumkin, chunki bu ulardan foydalanish juda muhim, garchi ular boshqa dasturlarga ega bo'lsa ham.[3][4]

Bu Python yordamida quyida keltirilgan. Birinchidan, rekursiya deb nomlangan standart:

def haqiqat(n):    agar n == 0:        qaytish 1    qaytish n * haqiqat(n - 1)

Yuqori darajadagi funktsiya yordamida yuqori darajadagi funktsiya argumentga noma'lum ravishda murojaat qiladi, ammo argument sifatida standart rekursiv funktsiyaga muhtoj:

def fakt0(n0):    agar n0 == 0:        qaytish 1    qaytish n0 * fakt0(n0 - 1)fakt1 = lambda f, n1: 1 agar n1 == 0 boshqa n1 * f(n1 - 1)haqiqat = lambda n: fakt1(fakt0, n)

Standart rekursiv funktsiyani funktsiya argumentini qo'ng'iroqqa o'tkazish orqali yo'q qilishimiz mumkin:

fakt1 = lambda f, n1: 1 agar n1 == 0 boshqa n1 * f(f, n1 - 1)haqiqat = lambda n: fakt1(fakt1, n)

Ikkinchi qatorni umumiy bilan almashtirish mumkin yuqori darajadagi funktsiya deb nomlangan kombinator:

F = lambda f: (lambda x: f(f, x))fakt1 = lambda f, n1: 1 agar n1 == 0 boshqa n1 * f(f, n1 - 1)haqiqat = F(fakt1)

Anonim tarzda yozilgan:[5]

(lambda f: (lambda x: f(f, x))) \(lambda g, n1: 1 agar n1 == 0 boshqa n1 * g(g, n1 - 1))

In lambda hisobi, faqat bitta o'zgaruvchining funktsiyalaridan foydalanadi, buni Y kombinatori. Avval ikkita o'zgaruvchining yuqori tartibli funktsiyasini bitta o'zgaruvchining funktsiyasi qiling, u to'g'ridan-to'g'ri funktsiyani qaytaradi qichqiriq:

fakt1 = lambda f: (lambda n1: 1 agar n1 == 0 boshqa n1 * f(f)(n1 - 1))haqiqat = fakt1(fakt1)

Bu erda ikkita "yuqori buyurtma funktsiyasini o'zi uchun qo'llash" operatsiyalari mavjud: f (f) birinchi qatorda va fakt1 (fakt1) ikkinchisida. Ikkinchi ikki tomonlama dasturni kombinator hosil:

C = lambda x: x(x)fakt1 = lambda f: (lambda n1: 1 agar n1 == 0 boshqa n1 * f(f)(n1 - 1))haqiqat = C(fakt1)

Ikki tomonlama dasturning samaradorligini aniqlash:

C = lambda x: x(x)D. = lambda f: (lambda x: f(lambda v: x(x)(v)))fakt1 = lambda g: (lambda n1: 1 agar n1 == 0 boshqa n1 * g(n1 - 1))haqiqat = C(D.(fakt1))

Ikkita kombinatorni birlashtirganda hosil bo'ladi Y kombinatori:

C = lambda x: x(x)D. = lambda f: (lambda x: f(lambda v: x(x)(v)))Y = lambda y: C(D.(y))fakt1 = lambda g: (lambda n1: 1 agar n1 == 0 boshqa n1 * g(n1 - 1))haqiqat = Y(fakt1)

Y kombinatorini kengaytirish natijasida hosil bo'ladi:

Y = lambda f: (lambda x: f(lambda v: x(x)(v))) \              (lambda x: f(lambda v: x(x)(v)))fakt1 = lambda g: (lambda n1: 1 agar n1 == 0 boshqa n1 * g(n1 - 1))haqiqat = Y(fakt1)

Bularni birlashtirish lambda hisob-kitobidagi faktorialning rekursiv ta'rifini beradi (bitta o'zgaruvchining noma'lum funktsiyalari):[6]

(lambda f: (lambda x: f(lambda v: x(x)(v)))           (lambda x: f(lambda v: x(x)(v)))) \(lambda g: (lambda n1: 1 agar n1 == 0 boshqa n1 * g(n1 - 1)))

Misollar

APL

Yilda APL, joriy dfn orqali kirish mumkin . Bu noma'lum rekursiyaga imkon beradi, masalan, faktorialni amalga oshirishda:

   {0=⍵:1  × -1} 5120   {0=⍵:1  × -1}¨ 10    0 0 dan 9 gacha bo'lgan har bir elementga qo'llaniladi1 1 2 6 24 120 720 5040 40320 362880

JavaScript

Yilda JavaScript, joriy funktsiyaga kirish mumkin argumentlar.callee, qo'ng'iroq qilish funktsiyasi orqali kirish mumkin argumentlar.caller. Bular noma'lum rekursiyaga imkon beradi, masalan, faktorialni amalga oshirishda:[2]

[1, 2, 3, 4, 5].xarita(funktsiya(n) {    qaytish (!(n > 1)) ? 1 : dalillar.kalli(n - 1) * n;});

Perl

Bilan boshlanadi Perl 5.16, joriy subroutinaga. Orqali kirish mumkin __SUB__ token, joriy dasturga havolani qaytaradigan yoki undef subroutine tashqarisida.[7] Bu noma'lum rekursiyaga imkon beradi, masalan quyidagi faktoriallarni amalga oshirishda:

#! / usr / bin / perlfoydalanish xususiyati ":5.16";chop etish sub {    mening $ x = siljish;    $ x > 0    ? $ x * __SUB__->( $ x - 1 )    : 1;}->(5), " n";

R

Yilda R, joriy funktsiyani yordamida chaqirish mumkin Eslatib o'tamiz. Masalan,

sapply(0:5, funktsiya(n) {  agar (n == 0) qaytish(1)  n * Eslatib o'tamiz(n - 1)})

Ammo bu ishlamaydi, ammo boshqa funktsiyaga argument sifatida o'tsa, masalan. lapply, anonim funktsiya ta'rifi ichida. Ushbu holatda, sys.function (0) foydalanish mumkin.[8] Masalan, quyidagi kod ro'yxatni rekursiv ravishda kvadratchalashtiradi:

(funktsiya(x) {  agar (is.list(x)) {    lapply(x, sys.funksiya(0))  } boshqa {    x ^ 2  }})(ro'yxat(ro'yxat(1, 2, 3), ro'yxat(4, 5)))

Adabiyotlar

  1. ^ 226-son: Go-da noma'lum funktsiyani vaqtinchalik echimlarsiz qaytarib bo'lmaydi.
  2. ^ a b javob bering muallifi olliej, '08 yil 25-oktabr "Nima uchun argument.callee.caller xususiyati JavaScript-da eskirgan? ", StackOverflow
  3. ^ Ushbu terminologiya asosan ko'rinadi folklor, lekin u quyidagicha ko'rinadi:
    • Trey Nesh, Tezlashtirilgan C # 2008, Apress, 2007 yil, ISBN  1-59059-873-3, p. 462—463. Asosan olingan Ues Dayer blog (keyingi bandga qarang).
    • Ues Dayer C # da anonim rekursiya 2007 yil 2 fevral. Yuqorida keltirilgan, ammo ko'proq munozaralar bilan birga keltirilgan, xuddi shunga o'xshash misolni o'z ichiga oladi.
  4. ^ Agar ishlayotgan bo'lsa Y kombinatorini chiqarish, 2008 yil 10-yanvar
  5. ^ Ugo Valterning javobi ga "Pythonda lambda funktsiyasi o'zini rekursiv deb atashi mumkinmi? "
  6. ^ Nuxning javobi ga "Pythonda lambda funktsiyasi o'zini rekursiv deb atashi mumkinmi? "
  7. ^ Perldoc "'Current_sub' xususiyati ", perldoc xususiyati
  8. ^ agstudy javobi ga Anonim rekursiv funktsiyani yozish uchun hozirda chaqirilgan funktsiyani oling da StackOverflow