В інформатиці анонімна рекурсія є рекурсією, у якій не використовується виклик функції по імені. Це може бути зроблено або явно, використовуючи функцію більш високого порядку - передаючи функцію як аргумент і викликаючи її, - чи неявно, за допомогою можливостей рефлексії, які дозволяють отримати доступ до певних функцій поточного [en], наприклад "поточну функцію", або "функцію що викликала поточну функцію".
У теоретичній інформатиці важлива анонімна рекурсія, оскільки вона показує, що можна реалізувати рекурсію, не вимагаючи іменованих функцій. Це особливо важливо для лямбда-числення, яке має анонімні унарні функції, але може обчислювати будь-яку рекурсивную функцію. Ця анонімна рекурсія може бути проведена в загальному за допомогою [en].
Використання
Анонімна рекурсія в першу чергу використовується для уможливлення рекурсії для анонімних функцій, особливо коли вони утворюють замикання або використовуються як зворотні виклики, щоб уникнути необхідності зв'язування імені функції.
Анонімна рекурсія в основному складається з виклику «поточної функції», що призводить до прямої рекурсії. Можлива анонімна непряма рекурсія, наприклад, шляхом виклику функції, що викликає (попередня функція) або, рідше, шляхом просування ще вище по стеку викликів.
Анонімна рекурсія також може використовуватися для іменованих функцій, коли вони викликаються не за іменем, а за "займенником" "поточна функція", аби уможливити перейменування без необхідності зміни назви в місці рекурсивного виклику.
Альтернативи
Іменовані функції
Типова альтернатива - використовувати іменовані функції і іменовану рекурсію. Для анонімної функції це можна зробити або шляхом прив'язки імені до функції, як у виразах іменованих функцій в JavaScript, або шляхом присвоєння функції змінної і подальшого виклику цієї змінної, як в операторах функції в JavaScript. Оскільки мови, які дозволяють анонімні функції, зазвичай дозволяють присвоювати ці функції змінним, багато мов відкидають анонімну рекурсію; приклади включають Go.
Наприклад, в JavaScript факторіал можна визначити через анонімну рекурсію ось так::
[1, 2, 3, 4, 5].map(function(n) { return (!(n > 1)) ? 1 : arguments.callee(n-1) * n; });
Це можна переписати використовуючи іменовану рекурсію:
[1, 2, 3, 4, 5].map(function factorial(n) { return (!(n > 1)) ? 1 : factorial(n-1) * n; });
Передача функцій як аргументів
Навіть без механізмів посилання на поточну функцію або функцію що її викликає, анонімна рекурсія можлива в мовах яка дозволяє функції як аргументи. Це робиться шляхом додавання іншого параметра до основної рекурсивної функції та використання цього параметра як функції для рекурсивного виклику. Це створює функцію вищого порядку, і передача цієї функції як аргумент самій собі дозволяє анонімну рекурсію в межах фактичної рекурсивної функції.
Це можна зробити повністю анонімно, застосувавши до цієї функції вищого порядку [en]. Це головним чином представляє академічний інтерес, особливо для того, щоб показати, що лямбда-числення має рекурсію, оскільки отриманий вираз значно складніший, ніж вихідна іменована рекурсивна функція. І навпаки, використання комбінаторів з нерухомою точкою загалом може називатися "анонімною рекурсією", оскільки це є найвідомішим їх використанням, хоча вони мають і інші застосування.
Продемонструємо це нижче, мовою Python. Спершу, стандартна іменована рекурсія:
def fact(n): if n == 0: return 1 return n * fact(n - 1)
Використовуючи функцію вищого порядку, що отримує сама себе як аргумент:
fact1 = lambda f, n1: 1 if n1 == 0 else n1 * f(f, n1 - 1) fact = lambda n: fact1(fact1, n)
Другий рядок може бути замінений загальною функцією вищого порядку, яка називається комбінатором:
F = lambda f: (lambda x: f(f, x)) fact1 = lambda f, n1: 1 if n1 == 0 else n1 * f(f, n1 - 1) fact = F(fact1)
Переписавши цей код анонімними функціями:
(lambda f: (lambda x: f(f, x))) \ (lambda g, n1: 1 if n1 == 0 else n1 * g(g, n1 - 1))
В лямбда-численні, яке використовує тільки функції однієї змінної, це може бути зроблено через . Спочатку створимо функцію вищого порядку двох змінних функцією однієї змінної, яка безпосередньо повертає функцію за допомогою каррінгу:
fact1 = lambda f: (lambda n1: 1 if n1 == 0 else n1 * f(f)(n1 - 1)) fact = fact1(fact1)
Тут є дві операції "застосування функції вищого порядку до самої себе": f(f)
у першому рядку та fact1(fact1)
у другому. Якщо розкласти друге подвійне застосування на комбінатор, вийде :
C = lambda x: x(x) fact1 = lambda f: (lambda n1: 1 if n1 == 0 else n1 * f(f)(n1 - 1)) fact = C(fact1)
Замінивши інші подвійні застосування, маємо:
C = lambda x: x(x) D = lambda f: (lambda x: f(lambda v: x(x)(v))) fact1 = lambda g: (lambda n1: 1 if n1 == 0 else n1 * g(n1 - 1)) fact = C(D(fact1))
Поєднання двох комбінаторів в один дає Y-комбінатор:
C = lambda x: x(x) D = lambda f: (lambda x: f(lambda v: x(x)(v))) Y = lambda y: C(D(y)) fact1 = lambda g: (lambda n1: 1 if n1 == 0 else n1 * g(n1 - 1)) fact = Y(fact1)
Заміна Y комбінатора визначенням:
Y = lambda f: (lambda x: f(lambda v: x(x)(v))) \ (lambda x: f(lambda v: x(x)(v))) fact1 = lambda g: (lambda n1: 1 if n1 == 0 else n1 * g(n1 - 1)) fact = Y(fact1)
Поєднуючи ці результати, ми отримуємо рекурсивне визначення факторіалу в лямбда-численні (анонімні функції однієї змінної):
(lambda f: (lambda x: f(lambda v: x(x)(v))) (lambda x: f(lambda v: x(x)(v)))) \ (lambda g: (lambda n1: 1 if n1 == 0 else n1 * g(n1 - 1)))
Приклади
APL
В APL поточна [en] доступна через ∇
. Це дозволяє анонімну рекурсію, наприклад, у цій реалізації факторіалу:
{0=⍵:1 ⋄ ⍵×∇ ⍵-1} 5 120 {0=⍵:1 ⋄ ⍵×∇ ⍵-1}¨ ⍳10 ⍝ applied to each element of 0 to 9 1 1 2 6 24 120 720 5040 40320 362880
JavaScript
У JavaScript поточна функція була доступна через arguments.callee
, тоді як функція виклику доступна через arguments.caller
. Вони дозволяють анонімну рекурсію, наприклад у цій реалізації факторіалу:
[1, 2, 3, 4, 5].map(function(n) { return (!(n > 1)) ? 1 : arguments.callee(n - 1) * n; });
Perl
Починаючи з Perl 5.16, поточна підпрограма доступна через __SUB__
, який повертає посилання на поточну підпрограму або undef
поза підпрограмою. Це дозволяє анонімну рекурсію, наприклад, при наступній реалізації факторіалу:
#!/usr/bin/perl use feature ":5.16"; print sub { my $x = shift; $x > 0 ? $x * __SUB__->( $x - 1 ) : 1; }->(5), "\n";
R
У R поточну функцію можна викликати за допомогою Recall
. Наприклад,
sapply(0:5, function(n) { if (n == 0) return(1) n * Recall(n - 1) })
Однак це не спрацює, при передачі іншій функції як аргумент, наприклад lapply
. У цьому випадку можна використати sys.function(0)
. Наприклад, наведений нижче код рекурсивно підносить всі значення списку до квадрату:
(function(x) { if (is.list(x)) { lapply(x, sys.function(0)) } else { x^2 } })(list(list(1, 2, 3), list(4, 5)))
Див. також
Зноски
- arguments.callee - JavaScript. MDN. 7 вересня 2023. Процитовано 11 лютого 2024.
- . Архів оригіналу за 8 березня 2014. Процитовано 15 листопада 2020.
- answer by olliej, Oct 25 '08 to "Why was the arguments.callee.caller property deprecated in JavaScript?", StackOverflow
- * Trey Nash, Accelerated C# 2008, Apress, 2007, , p. 462—463. Derived substantially from Wes Dyer's blog (see next item).
- Wes Dyer Anonymous Recursion in C# [ 18 січня 2010 у Wayback Machine.], February 02, 2007, contains a substantially similar example found in the book above, but accompanied by more discussion.
- The If Works Deriving the Y combinator [ 26 серпня 2009 у Wayback Machine.], January 10th, 2008
- Відповідь Hugo Walter-са на питання "Can a lambda function call itself recursively in Python?"
- Nux's answer to "Can a lambda function call itself recursively in Python?"
- Function.prototype.caller - JavaScript | MDN. MDN. 12 квітня 2023. Процитовано 11 лютого 2024.
Вікіпедія, Українська, Україна, книга, книги, бібліотека, стаття, читати, завантажити, безкоштовно, безкоштовно завантажити, mp3, відео, mp4, 3gp, jpg, jpeg, gif, png, малюнок, музика, пісня, фільм, книга, гра, ігри, мобільний, телефон, android, ios, apple, мобільний телефон, samsung, iphone, xiomi, xiaomi, redmi, honor, oppo, nokia, sonya, mi, ПК, web, Інтернет
V informatici anonimna rekursiya ye rekursiyeyu u yakij ne vikoristovuyetsya viklik funkciyi po imeni Ce mozhe buti zrobleno abo yavno vikoristovuyuchi funkciyu bilsh visokogo poryadku peredayuchi funkciyu yak argument i viklikayuchi yiyi chi neyavno za dopomogoyu mozhlivostej refleksiyi yaki dozvolyayut otrimati dostup do pevnih funkcij potochnogo en napriklad potochnu funkciyu abo funkciyu sho viklikala potochnu funkciyu U teoretichnij informatici vazhliva anonimna rekursiya oskilki vona pokazuye sho mozhna realizuvati rekursiyu ne vimagayuchi imenovanih funkcij Ce osoblivo vazhlivo dlya lyambda chislennya yake maye anonimni unarni funkciyi ale mozhe obchislyuvati bud yaku rekursivnuyu funkciyu Cya anonimna rekursiya mozhe buti provedena v zagalnomu za dopomogoyu en VikoristannyaAnonimna rekursiya v pershu chergu vikoristovuyetsya dlya umozhlivlennya rekursiyi dlya anonimnih funkcij osoblivo koli voni utvoryuyut zamikannya abo vikoristovuyutsya yak zvorotni vikliki shob uniknuti neobhidnosti zv yazuvannya imeni funkciyi Anonimna rekursiya v osnovnomu skladayetsya z vikliku potochnoyi funkciyi sho prizvodit do pryamoyi rekursiyi Mozhliva anonimna nepryama rekursiya napriklad shlyahom vikliku funkciyi sho viklikaye poperednya funkciya abo ridshe shlyahom prosuvannya she vishe po steku viklikiv Anonimna rekursiya takozh mozhe vikoristovuvatisya dlya imenovanih funkcij koli voni viklikayutsya ne za imenem a za zajmennikom potochna funkciya abi umozhliviti perejmenuvannya bez neobhidnosti zmini nazvi v misci rekursivnogo vikliku AlternativiImenovani funkciyi Tipova alternativa vikoristovuvati imenovani funkciyi i imenovanu rekursiyu Dlya anonimnoyi funkciyi ce mozhna zrobiti abo shlyahom priv yazki imeni do funkciyi yak u virazah imenovanih funkcij v JavaScript abo shlyahom prisvoyennya funkciyi zminnoyi i podalshogo vikliku ciyeyi zminnoyi yak v operatorah funkciyi v JavaScript Oskilki movi yaki dozvolyayut anonimni funkciyi zazvichaj dozvolyayut prisvoyuvati ci funkciyi zminnim bagato mov vidkidayut anonimnu rekursiyu prikladi vklyuchayut Go Napriklad v JavaScript faktorial mozhna viznachiti cherez anonimnu rekursiyu os tak 1 2 3 4 5 map function n return n gt 1 1 arguments callee n 1 n Ce mozhna perepisati vikoristovuyuchi imenovanu rekursiyu 1 2 3 4 5 map function factorial n return n gt 1 1 factorial n 1 n Peredacha funkcij yak argumentiv Navit bez mehanizmiv posilannya na potochnu funkciyu abo funkciyu sho yiyi viklikaye anonimna rekursiya mozhliva v movah yaka dozvolyaye funkciyi yak argumenti Ce robitsya shlyahom dodavannya inshogo parametra do osnovnoyi rekursivnoyi funkciyi ta vikoristannya cogo parametra yak funkciyi dlya rekursivnogo vikliku Ce stvoryuye funkciyu vishogo poryadku i peredacha ciyeyi funkciyi yak argument samij sobi dozvolyaye anonimnu rekursiyu v mezhah faktichnoyi rekursivnoyi funkciyi Ce mozhna zrobiti povnistyu anonimno zastosuvavshi do ciyeyi funkciyi vishogo poryadku en Ce golovnim chinom predstavlyaye akademichnij interes osoblivo dlya togo shob pokazati sho lyambda chislennya maye rekursiyu oskilki otrimanij viraz znachno skladnishij nizh vihidna imenovana rekursivna funkciya I navpaki vikoristannya kombinatoriv z neruhomoyu tochkoyu zagalom mozhe nazivatisya anonimnoyu rekursiyeyu oskilki ce ye najvidomishim yih vikoristannyam hocha voni mayut i inshi zastosuvannya Prodemonstruyemo ce nizhche movoyu Python Spershu standartna imenovana rekursiya def fact n if n 0 return 1 return n fact n 1 Vikoristovuyuchi funkciyu vishogo poryadku sho otrimuye sama sebe yak argument fact1 lambda f n1 1 if n1 0 else n1 f f n1 1 fact lambda n fact1 fact1 n Drugij ryadok mozhe buti zaminenij zagalnoyu funkciyeyu vishogo poryadku yaka nazivayetsya kombinatorom F lambda f lambda x f f x fact1 lambda f n1 1 if n1 0 else n1 f f n1 1 fact F fact1 Perepisavshi cej kod anonimnimi funkciyami lambda f lambda x f f x lambda g n1 1 if n1 0 else n1 g g n1 1 V lyambda chislenni yake vikoristovuye tilki funkciyi odniyeyi zminnoyi ce mozhe buti zrobleno cherez Spochatku stvorimo funkciyu vishogo poryadku dvoh zminnih funkciyeyu odniyeyi zminnoyi yaka bezposeredno povertaye funkciyu za dopomogoyu karringu fact1 lambda f lambda n1 1 if n1 0 else n1 f f n1 1 fact fact1 fact1 Tut ye dvi operaciyi zastosuvannya funkciyi vishogo poryadku do samoyi sebe f f u pershomu ryadku ta fact1 fact1 u drugomu Yaksho rozklasti druge podvijne zastosuvannya na kombinator vijde C lambda x x x fact1 lambda f lambda n1 1 if n1 0 else n1 f f n1 1 fact C fact1 Zaminivshi inshi podvijni zastosuvannya mayemo C lambda x x x D lambda f lambda x f lambda v x x v fact1 lambda g lambda n1 1 if n1 0 else n1 g n1 1 fact C D fact1 Poyednannya dvoh kombinatoriv v odin daye Y kombinator C lambda x x x D lambda f lambda x f lambda v x x v Y lambda y C D y fact1 lambda g lambda n1 1 if n1 0 else n1 g n1 1 fact Y fact1 Zamina Y kombinatora viznachennyam Y lambda f lambda x f lambda v x x v lambda x f lambda v x x v fact1 lambda g lambda n1 1 if n1 0 else n1 g n1 1 fact Y fact1 Poyednuyuchi ci rezultati mi otrimuyemo rekursivne viznachennya faktorialu v lyambda chislenni anonimni funkciyi odniyeyi zminnoyi lambda f lambda x f lambda v x x v lambda x f lambda v x x v lambda g lambda n1 1 if n1 0 else n1 g n1 1 PrikladiAPL V APL potochna en dostupna cherez Ce dozvolyaye anonimnu rekursiyu napriklad u cij realizaciyi faktorialu 0 1 1 5 120 0 1 1 10 applied to each element of 0 to 9 1 1 2 6 24 120 720 5040 40320 362880 JavaScript U JavaScript potochna funkciya bula dostupna cherez arguments callee todi yak funkciya vikliku dostupna cherez arguments caller Voni dozvolyayut anonimnu rekursiyu napriklad u cij realizaciyi faktorialu 1 2 3 4 5 map function n return n gt 1 1 arguments callee n 1 n Perl Pochinayuchi z Perl 5 16 potochna pidprograma dostupna cherez SUB yakij povertaye posilannya na potochnu pidprogramu abo undefpoza pidprogramoyu Ce dozvolyaye anonimnu rekursiyu napriklad pri nastupnij realizaciyi faktorialu usr bin perl use feature 5 16 print sub my x shift x gt 0 x SUB gt x 1 1 gt 5 n R U R potochnu funkciyu mozhna viklikati za dopomogoyu Recall Napriklad sapply 0 5 function n if n 0 return 1 n Recall n 1 Odnak ce ne spracyuye pri peredachi inshij funkciyi yak argument napriklad lapply U comu vipadku mozhna vikoristati sys function 0 Napriklad navedenij nizhche kod rekursivno pidnosit vsi znachennya spisku do kvadratu function x if is list x lapply x sys function 0 else x 2 list list 1 2 3 list 4 5 Div takozhRekursiya Anonimna funkciyaZnoskiarguments callee JavaScript MDN 7 veresnya 2023 Procitovano 11 lyutogo 2024 Arhiv originalu za 8 bereznya 2014 Procitovano 15 listopada 2020 answer by olliej Oct 25 08 to Why was the arguments callee caller property deprecated in JavaScript StackOverflow Trey Nash Accelerated C 2008 Apress 2007 ISBN 1 59059 873 3 p 462 463 Derived substantially from Wes Dyer s blog see next item Wes Dyer Anonymous Recursion in C 18 sichnya 2010 u Wayback Machine February 02 2007 contains a substantially similar example found in the book above but accompanied by more discussion The If Works Deriving the Y combinator 26 serpnya 2009 u Wayback Machine January 10th 2008 Vidpovid Hugo Walter sa na pitannya Can a lambda function call itself recursively in Python Nux s answer to Can a lambda function call itself recursively in Python Function prototype caller JavaScript MDN MDN 12 kvitnya 2023 Procitovano 11 lyutogo 2024