Опашката рекурсия в Скала

В този пост ще говорим за интересен фиш функционално програмиране - на рекурсия на опашка. Но първо, нека да си спомним какво общото рекурсия. Така че рекурсия - описание на определен обект, който е неразделна част от себе си. Например, един математически израз може да съдържа цифрови операнди, аритметика и други математически изрази.

В тази статия ние се сблъскваме с рекурсивни функции. За да разберете стойността на такава функция за определен набор от входни параметри, необходими за определянето на стойността на тази функция за различен набор от входни параметри. С други думи, функция, която нарича себе си. Най-известният пример на рекурсия е факториел (така казват повечето учебници по програмиране) и числата на Фибоначи. Забравете за факториелите и да видим как изглежда изпълнението на числата на Фибоначи в Java:

Както се вижда от примера, преди връщане на стойност от функция обаждане се извършва два от една и съща функция, но с различни стойности.

опашката рекурсия

Сега обратно към опашката рекурсивния. Рекурсия е на опашката, ако обаждането е рекурсивна функция ще бъде последната операция преди да се върне. Нека да пренапише предишния пример с помощта на опашката рекурсия:

API на класа се е променила: ние все още имаме метод, който връща номера на п-ия Фибоначи. Също така ние имаме нов частен метод fibIter. който включва опашка рекурсия. Много често, за неговото изпълнение, метод на помощник, който се състоянието преди следващата итерация на рекурсията. С тази опашка рекурсия може да се представи като цикъл:

Този код изглежда ужасно и има много места, където можете да се обърка, така че често предпочитан рекурсивни функции поради тяхната краткост и четливост.

Нека разгледайте нашите функции по време на битка и брои 10 000-ия елемент от последователността. За наше огорчение, двата метода - и ПИБ. и fibWithTailRec - хвърлят java.lang.StackOverflowError. Това предполага, че използването на рекурсия в Java да внимателно. И не забравяйте за начина на използване на линия :)

Скала на помощ

И това, което те мислят за рекурсия други езици JVM? Нека да видим как стоят нещата в Скала с рекурсивни функции и пренаписване на двете рекурсивни изпълнението на кода, като се има предвид числата на Фибоначи. Нека се опитаме да направим най-сходния в изпълнение на същите функции:

И сега отново да разчита на Фибоначи номер 10000, но в Скала. Оказва се, че версията на опашката-рекурсивни успешно се справи със задачата. Каква е разликата между почти "едно и също" код в Java и Scala. Нека да погледнем на байт кода от тези методи (javap -C) и проверете какво всъщност трябва да правят компилатори:

Scala компилатор осъзнах, че тази опашка рекурсия, и се разпространява рекурсивно извикване на функция в цикъла, който, както видяхме по-рано, за да напишете не толкова хубаво.

Светът никога няма да е същото

Така че, ние вече знаем как стръмен опашка рекурсия. Време е да се прилагат тези знания. Светът на ОП, нито една програма не е завършено без списък. Опитайте се да осъзнаят, независимо намотка - един от основните операции, включени в списъка (Scala ни предлага две версии - в ляво и дясно) (Той е известен и като се намали стадото.):

Както можете да видите, и двете функции са рекурсивни, но, за ужас на ужасите, foldRight не опашка рекурсия, така че ние сме изправени пред преливане стак. Налице е сравнително просто решение, което е, разбира се, изисква допълнителни разходи, но това не влошава сложността на алгоритъм. Пишем правото на намотка чрез извиване на ляво:

Ако ние не вярваме, ще бъде нашата функция е оптимизиран или не, и ние бихме много сте харесали, можете да използвате анотация @tailrec. А доста често срещано мнение е, че екип от компилатора да направи опашка рекурсия в метод. Но това не е (особено след като преобразуване не винаги е възможно). Това прави само проверка дали маркирани си игрален опашка рекурсия, и ако не, ще има грешка компилация. Причините за това малко и те са лесно да се провери:

  • това не е окончателно метод, което означава, че може да се замени в подкласове
  • методът не се предизвика, т.е. това не е рекурсивно
  • това не е опашка рекурсия.

Опашката рекурсия в Скала
Mobile-първо, или слуховете за смъртта на работния плот са силно преувеличени?

Опашката рекурсия в Скала
SEO за клиент: трябва да знаете?