Rekurencja: da się ignorować pojedyńczą instrukcję?

Odpowiedz Nowy wątek
2019-02-06 03:13
0

Mam jakąś funkcję typu void, która ma się rekurencyjnie wykonywać w nieskończoność. Przykładowo:

void recursion()
{
    std::cout << "Ala ma kota\n";

    std::cout << "Ala ma psa\n";
    recursion();
}

Chciałbym aby pierwsza instrukcja tj. std::cout << "Ala ma kota\n"; wykonała się tylko raz (lub N razy). Ale właśnie: jak to ograniczyć, żeby wykonało się tylko raz?

Koniecznie nie chcę przekazywać żadnych dodatkowych parametrów, ani korzystać z zmiennych spoza ciała funkcji. Cała reszta dozwolona.

Z zmienną spoza ciała funkcji można to rozwiązać (niekoniecznie kulturalnie) np. tak:

bool didRecursionStart = false;
void recursion()
{
    if (!didRecursionStart)
        std::cout << "Ala ma kota\n";

    std::cout << "Ala ma psa\n";
    didRecursionStart = true;
    recursion();
}

ale definiując ją w środku ciała funkcji będzie się to nadpisywać i nie zadziała. Próbowałem też robić liczniki, które działałyby na podobnej zasadzie, ale też definicja się jakby nadpisuje.

Jakiś pomysł?

Pozostało 580 znaków

2019-02-06 03:18
2
Hodor napisał(a):

Koniecznie nie chcę przekazywać żadnych dodatkowych parametrów, ani korzystać z zmiennych spoza ciała funkcji. Cała reszta dozwolona.

Nie ma żadnej reszty – ta informacja nie może być lokalna, więc masz do wyboru albo przekazanie jej w parametrze, albo wydzielenie do globalnej zmiennej.

Mam jakąś funkcję typu void, która ma się rekurencyjnie wykonywać w nieskończoność.

Rekurencja i nieskończoność…?


edytowany 1x, ostatnio: furious programming, 2019-02-06 03:19
Czyli tego się po prostu nie da zrobić z tymi warunkami, które sobie wymyśliłem? - Hodor 2019-02-06 03:23
Da się ze static, ale tylko raz na całą instancję procesu. Ale skoro ma ona działać w nieskończoność, to nie ma problemu. ;) - furious programming 2019-02-06 08:32

Pozostało 580 znaków

2019-02-06 03:52
1

Wydaje mi się, że tak, jak to Opisałeś, to sie nie da. Nurtuja mnie dwie rzeczy: czemu się Bronisz, przed przesyłaniem parametrów? Po co to w ogóle robić, przecież program drukujący coś w nieskończoność, nie jest nawet poprawnym programem.


Pokaż pozostałe 3 komentarze
Skończoność, nieskończoność - bez różnicy. Szukałem rozwiązania tego problemu, a nie potencjalnego znalezienia alternatywnego rozwiązania, choć doceniam i dziękuję. :P Po co to robię to jeszcze nie wiem, może się kiedyś do czegoś przyda, po prostu taki problem sobie wymyśliłem rozwiązując inny problem. Co do parametrów: bo wtedy byłoby za łatwo, i nie miałbym problemu, a chciałem skomplikować - może jakiś nowy trik bym poznał. :P - Hodor 2019-02-06 05:44
@hauleth: Tak, tak, tak, wiem, OSy, etc... Chodziło mi raczej o algorytm, który ma odpowiedzieć na jakieś pytanie, podać wynik... - lion137 2019-02-06 11:23
yes jest generatorem sekwencji, ponoć użyteczne w FP, przykład: https://thecannycoder.wordpress.com/2014/07/04/generators/ - vpiotr 2019-02-07 08:19
@lion137: czasem podawanie wyniku w nieskończoność jest rozwiązaniem, przykład dowolne iteratory po cyklach czy przetwarzanie strumieniowe, które kończy się wtedy gdy skończą się dane, ale algorytm sam z siebie nie zakłada nigdzie, że się skończy. - hauleth 2019-02-07 13:39
@hauleth: Tak, jak najbardziej, tylko, że nigdy nie zakładamy, nie zaobserwujemy, działania generatora w nieskończoniość. - lion137 2019-02-07 14:45

Pozostało 580 znaków

2019-02-06 05:00

Wydaje mi się, że potrzebujesz zmiennej statycznej w tej funkcji.

Tutaj przykład (co prawda w C ale to bez znaczenia): LINK

Pozostało 580 znaków

2019-02-06 05:50
0

@Mc_Hammer:

Dzięki, nie znałem tego keywordu static. "Ala ma kota" wykonuje się teraz tylko raz.

void recursion()
{
    static bool didRecursionStart = false;
    if (!didRecursionStart)
        std::cout << "Ala ma kota" << std::endl;

    std::cout << "Ala ma psa" << std::endl;
    didRecursionStart = true;
    recursion();
}

Pozostało 580 znaków

2019-02-06 08:37
2

Spoko, ale jeśli Twoja rekursja kiedyś by się skończyła (dodałbyś sposób na zakończenie) i chciałbyś ją uruchomić ponownie, to zmienna statyczna wciąż będzie true, więc Ala ma kota nie zostanie wypisane. Musisz przy takim kodzie bardzo uważać, np. żeby przy zakończeniu rekursji, ustawić zmienną statyczną na jej początkową wartość.

Na razie to anty-wzorzec ;)

Napisałem prosty test, jakbyś chciał to sprawdzić nie wywalając apki (przez nieskończoną rekursję):

#include <iostream>

int counter = 0;

void recursion()
{
    static bool didRecursionStart = false;
    if (!didRecursionStart)
        std::cout << "Ala ma kota" << std::endl;

    std::cout << "Ala ma psa" << std::endl;
    didRecursionStart = true;
    counter++;
    if (counter < 10) {
        recursion();
    }
    else {
        counter = 0;
    }
}

int main()
{
    std::cout << "Hello World!\n"; 
    recursion();
    std::cout << std::endl;
    recursion();
}
edytowany 4x, ostatnio: Spine, 2019-02-06 08:39

Pozostało 580 znaków

2019-02-06 09:48
10

Tak na prawdę, to sposobem który lepiej wyraża intencje (czyli kod ma się wykonać na początku) byłoby zrobienie dwóch funkcji.

void startRecursion() {
    std::cout << "Ala ma kota" << std::endl;
    recursion();
} 

void recursion()
{
    std::cout << "Ala ma psa" << std::endl;
    recursion();
}

Zobaczcie ile niepotrzebnego szumu zniknęło.

Teraz wystarczy wykonać startRecursion().


char mander; bool basaur;
Zaawansowana biblioteka T-Regx do wyrażeń regularnych w PHP
edytowany 2x, ostatnio: TomRiddle, 2019-02-06 10:36
na dodatek nie ma ukrytego stanu (zmiennej globalnej). - MarekR22 2019-02-06 10:34

Pozostało 580 znaków

2019-02-06 11:17
2

Mom zdaniem najlepszą opcją jest rozłożenie tego na 2 funkcje. Bardziej zastanawia mnie co chcesz zrobić z przepełnieniem stosu. C++ optymalizuje taką rekurencję? Może przechwycisz sygnał sigsegv? :)

W Pythonie można zwiększać recursion limit https://docs.python.org/3/lib[...]ys.html#sys.setrecursionlimit - ale to też działa do pewnego stopnia :D - Spine 2019-02-06 11:40
Co ma do tego python? Pytanie zdaje się dotyczy c++. I podejrzewam że jest taka opcja, nawet dla C GCC oferuje taką optymalizację. - elwis 2019-02-06 12:01
Spoko, ja tylko piszę z czym się zetknąłem w innym języku, dlatego w komentarzu :) - Spine 2019-02-06 12:18

Pozostało 580 znaków

2019-02-06 11:32
2
elwis napisał(a):

Mom zdaniem najlepszą opcją jest rozłożenie tego na 2 funkcje. Bardziej zastanawia mnie co chcesz zrobić z przepełnieniem stosu. C++ optymalizuje taką rekurencję? Może przechwycisz sygnał sigsegv? :)

kompilator pewnie zrobi z tego tail call

Pozostało 580 znaków

2019-02-06 14:17
1
TomRiddle napisał(a):

Tak na prawdę, to sposobem który lepiej wyraża intencje (czyli kod ma się wykonać na początku) byłoby zrobienie dwóch funkcji.

void startRecursion() {
    std::cout << "Ala ma kota" << std::endl;
    recursion();
} 

void recursion()
{
    std::cout << "Ala ma psa" << std::endl;
    recursion();
}

Zobaczcie ile niepotrzebnego szumu zniknęło.

Teraz wystarczy wykonać startRecursion().

Zgadza się, rozwiązanie chyba najbardziej eleganckie, ale tylko jeśli OP akceptuje brak kontroli nad ilością wykonań.

Hodor napisał(a):

Chciałbym aby pierwsza instrukcja (...) wykonała się tylko raz (lub N razy).

@Mc_Hammer: W początkowym rozwiązaniu również nie. Poza tym do funkcji można łatwo przekazać parametr, nie mówiąc o tym że funkcje rekurencyjne często same ustają swój koniec. - TomRiddle 2019-02-06 14:50

Pozostało 580 znaków

2019-02-06 20:24
2
Hodor napisał(a):

Mam jakąś funkcję typu void, która ma się rekurencyjnie wykonywać w nieskończoność. Przykładowo:
....
Jakiś pomysł?

Tak, najlepszy pomysł to nie robić tego wcale. Przecież po pewnym czasie przepełni Ci się stos i na tym etapie powinno się skończyć te dywagacje...

edytowany 1x, ostatnio: Mr.YaHooo, 2019-02-06 20:25

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0