Implementierung einer rekursiven Funktion

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
Antworten
Kay
Beiträge: 134
Registriert: So 14. Nov 2010, 15:17

Implementierung einer rekursiven Funktion

Beitrag von Kay »

Hallo,

ich habe ein Problem bei der Implementierung einer rekursiven Funktion.
Das folgende Beispiel hat in dieser Form natürlich keine praktiche Anwendung, es demonstriert lediglich meinen Versuch eine Rekursion zu bauen.
Die Funktion soll eigentlich die Zeichenfolge "funktioniert" liefern, passieren tut allerdings gar nichts. Ich hatte auch schon ein ShowMessage an den Anfang der Funktion gesetzt um herauszufinden, wie oft die Funktion aufgerufen wird. Es erscheint nur einmal eine Meldung, normalerweise müssten es jedoch 2 Aufrufe sein.

Code: Alles auswählen

unit unit1;
 
{$mode objfpc}{$H+}
 
interface
 
type
  TForm1 = class(TForm)
    procedure FormShow(Sender: TObject);
  private
    { private declarations }
    MaxValue: Integer;
    function Test: String;
  public
    { public declarations }
  end;
 
var
  Form1: TForm1; 
 
implementation
 
{$R *.lfm}
 
function TForm1.Test: String;
var
  Value: Integer;
begin
  if MaxValue = 0 then
  begin
    Result := 'funktioniert';
    Exit;
  end;
  Value := 1;
  repeat
    Inc(Value);
  until Value = MaxValue;
  MaxValue := 0;
  Result := Test;
end;
 
procedure TForm1.FormShow(Sender: TObject);
begin
  MaxValue := 10;
  ShowMessage(Test);
end;
 
end.
Ich hoffe mir kann jemand weiterhelfen.

Vielen Dank schonmal und viele Grüße
Kay
Zuletzt geändert von Lori am Fr 7. Dez 2012, 17:12, insgesamt 1-mal geändert.
Grund: Bitte den richtigen Highlighter verwenden.

u-boot
Beiträge: 309
Registriert: Do 9. Apr 2009, 10:10
OS, Lazarus, FPC: Ubuntu 9.10 (L 0.9.28 FPC 2.2.4)
CPU-Target: 32Bit
Wohnort: 785..

Re: Implementierung einer rekursiven Funktion

Beitrag von u-boot »

Kay hat geschrieben:Die Funktion soll eigentlich die Zeichenfolge "funktioniert" liefern, passieren tut allerdings gar nichts.
Kay hat geschrieben:Es erscheint nur einmal eine Meldung, normalerweise müssten es jedoch 2 Aufrufe sein.
hmm die beiden Aussagen widersprechen sich etwas. Ich gehe mal davon aus, dass die 2. stimmt:

Ich sehe, dass nur ein ShowMessage aufgerufen wird und ich sehe sonst nix, was eine weitere Meldung produzieren würde.
Von daher verstehe ich nicht wie aus deinem Quelltext 2 Meldungen entstehen sollten.
Ubuntu 9.10 (L 0.9.28 FPC 2.4.x)

TheBlackSheep70
Beiträge: 4
Registriert: Fr 7. Dez 2012, 08:38

Re: Implementierung einer rekursiven Funktion

Beitrag von TheBlackSheep70 »

Wie u-boot schon schrieb: die Funktion ShowMessage(...) wird nur einmal aufgerufen. Damit kann auch nur eine Nachricht angezeigt werden. Die Funktion Test wird zweimal durchlaufen und erst beim zweiten Durchlauf wird das Ergebnis 'funktioniert' geliefert.

Jetzt wäre es hilfreich zu wissen, was Deine Erwartung an den Code war, um helfen zu können.
Ich bin für das verantwortlich, was ich schreibe. Nicht für das, was Du interpretierst.

Benutzeravatar
theo
Beiträge: 11383
Registriert: Mo 11. Sep 2006, 19:01

Re: Implementierung einer rekursiven Funktion

Beitrag von theo »

Ohne Parameter ergibt das keinen Sinn. Irgendwie sowas:

Code: Alles auswählen

 
function Test(value:integer): String;
begin
  //writeln(MaxValue);
  if MaxValue = 0 then
  begin
    Result := inttostr(Value);
    Exit;
  end;
  Value := Maxvalue;
  MaxValue := 0;
  Result := Test(Value);
end;
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  MaxValue := 10;
  ShowMessage(Test(0));
end;   

TheBlackSheep70
Beiträge: 4
Registriert: Fr 7. Dez 2012, 08:38

Re: Implementierung einer rekursiven Funktion

Beitrag von TheBlackSheep70 »

theo hat geschrieben:Ohne Parameter ergibt das keinen Sinn. Irgendwie sowas:

Code: Alles auswählen

 
function Test(value:integer): String;
begin
  //writeln(MaxValue);
  if MaxValue = 0 then
  begin
    Result := inttostr(Value);
    Exit;
  end;
  Value := Maxvalue;
  MaxValue := 0;
  Result := Test(Value);
end;
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  MaxValue := 10;
  ShowMessage(Test(0));
end;   
Was allerdings am Programm-Ablauf nichts ändert. Immer noch nur eine Message und immer noch genau zwei Aufrufe der Funktion Test. Nur das Ergebnis hat sich von 'funktioniert' auf '10' geändert.

Es ist sicherlich der bessere Stil, der rekursiven Funktion einen Parameter zu übergeben und diesen für die Abbruchbedingung zu verwenden. Wie Du siehst, geht es aber auch mit einer globaleren Variablen ;-)
Ich bin für das verantwortlich, was ich schreibe. Nicht für das, was Du interpretierst.

Antrepolit
Beiträge: 340
Registriert: Di 12. Sep 2006, 08:57
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit
Kontaktdaten:

Re: Implementierung einer rekursiven Funktion

Beitrag von Antrepolit »

Code: Alles auswählen

 
  if MaxValue = 0 then
  begin
    Result := 'funktioniert';
    Exit;
  end;
 
kann doch auch nicht gehen, da MaxValue immer 10.

Code: Alles auswählen

 
  if [b]VALUE[/b]= 0 then
  begin
    Result := 'funktioniert';
    Exit;
  end;
 
Sollte gehen.
Grüße, Antrepolit

care only if your os is really burning

Benutzeravatar
theo
Beiträge: 11383
Registriert: Mo 11. Sep 2006, 19:01

Re: Implementierung einer rekursiven Funktion

Beitrag von theo »

TheBlackSheep70 hat geschrieben:  Was allerdings am Programm-Ablauf nichts ändert. Immer noch nur eine Message und immer noch genau zwei Aufrufe der Funktion Test. Nur das Ergebnis hat sich von 'funktioniert' auf '10' geändert.

Es ist sicherlich der bessere Stil, der rekursiven Funktion einen Parameter zu übergeben und diesen für die Abbruchbedingung zu verwenden. Wie Du siehst, geht es aber auch mit einer globaleren Variablen ;-)
Klugscheißern? :wink:
Stimmt nicht, im ersten Fall war die Message Box leer und Value als lokale Variable komplett sinnfrei.
Das Beispiel sieht schon eher wie ein Rekursion aus.

Vor Allem aber ist:
Result := Test(); //Auch ohne Parameter
und
Result := Test;

Im ObjFpc Modus nicht das gleiche.

TheBlackSheep70
Beiträge: 4
Registriert: Fr 7. Dez 2012, 08:38

Re: Implementierung einer rekursiven Funktion

Beitrag von TheBlackSheep70 »

theo hat geschrieben: im ersten Fall war die Message Box leer
Bei mir wurde 'funktioniert' in einer MessageBox angezeigt. Muss auch aufgrund des Codings so sein. Alles andere wäre ein Fehler beim Compilieren.
theo hat geschrieben:Value als lokale Variable komplett sinnfrei.
Hier hast Du recht. Die 4 Zeile hätte der Threaderöffner sparen können (und nicht nur diese vier Zeilen)
theo hat geschrieben:Das Beispiel sieht schon eher wie ein Rekursion aus.
Es ist nicht entscheidend, ob es wie eine Rekursion aussieht, sondern, ob es eine Rekursion ist. Und das ist sie auch im Eröffnungsthread.
Ich bin für das verantwortlich, was ich schreibe. Nicht für das, was Du interpretierst.

TheBlackSheep70
Beiträge: 4
Registriert: Fr 7. Dez 2012, 08:38

Re: Implementierung einer rekursiven Funktion

Beitrag von TheBlackSheep70 »

Antrepolit hat geschrieben:

Code: Alles auswählen

 
  if MaxValue = 0 then
  begin
    Result := 'funktioniert';
    Exit;
  end;
 
kann doch auch nicht gehen, da MaxValue immer 10.
Das ist so nicht richtig, denn mit:

Code: Alles auswählen

 
  MaxValue := 0;
  Result := Test;
 
wird MaxValue auf 0 gesetzt, bevor sich die Funktion Test selbst aufruft.
Ich bin für das verantwortlich, was ich schreibe. Nicht für das, was Du interpretierst.

Benutzeravatar
theo
Beiträge: 11383
Registriert: Mo 11. Sep 2006, 19:01

Re: Implementierung einer rekursiven Funktion

Beitrag von theo »

TheBlackSheep70 hat geschrieben:
theo hat geschrieben: im ersten Fall war die Message Box leer
Bei mir wurde 'funktioniert' in einer MessageBox angezeigt. Muss auch aufgrund des Codings so sein. Alles andere wäre ein Fehler beim Compilieren.
Dann hast du aber den mode delphi drin oder einen alten Compiler (k.A.).
Könntest du bitte etwas weniger großspurig sein? Danke!
TheBlackSheep70 hat geschrieben: Es ist nicht entscheidend, ob es wie eine Rekursion aussieht, sondern, ob es eine Rekursion ist. Und das ist sie auch im Eröffnungsthread.
Könntest du bitte etwas weniger großspurig sein? Danke!

Kay
Beiträge: 134
Registriert: So 14. Nov 2010, 15:17

Re: Implementierung einer rekursiven Funktion

Beitrag von Kay »

@Antrepolit:
Wie ja schon geschrieben wurde, setze ich die Variable MaxValue vor dem erneuten Funktionsaufruf auf 0 und schaffe somit das Abbruchkriterium. Es entsteht also keine Endlosschleife.

zur Sinnhaftigkeit:
Das ist absolut korrekt. Wie ich in meinem Eröffnungsthread auch geschrieben habe, hat das Beispiel in dieser Form keine praktische Anwendung. Ich habe hier lediglich einen Ausschnitt aus meinem Projekt genommen und verändert. Natürlich wäre auch die Schleife hier überflüssig, aber in meinem Programm erfolgen dort noch einige andere Berechnungen. Also nicht weiter über den Sinn nachdenken, mir geht es nur um das Konstrukt und Einfluss auf die Rekursion hat es jedenfalls nicht.

zu ShowMessage:
Natürlich wird ShowMessage in der Methode FormShow nur einmal aufgerufen. Was ich meinte ist, dass ich eine weitere ShowMessage an den Anfang der Test-Funktion gesetzt hatte, um die Anzahl der Aufrufe zählen zu können, also

Code: Alles auswählen

function TForm1.Test: String;
begin
  ShowMessage('Aufruf');
  ...
end;
Mein Problem ist nun, dass die ShowMessage in FormShow leer ist und die Test-Funktion nur einmal aufgerufen wird und nicht zweimal wie zu erwarten wäre.

Kay

Kay
Beiträge: 134
Registriert: So 14. Nov 2010, 15:17

Re: Implementierung einer rekursiven Funktion

Beitrag von Kay »

OK, ich hab die Rekursion jetzt hinbekommen:

Code: Alles auswählen

Result := Test();
Muss man denn in Free Pascal jetzt jeden Funktionsaufruf mit den leeren Klammern angeben, also auch beim Aufruf von beispielsweise übergeordneten Konstruktoren oder Destruktoren in eigenen Klassen, z. B.

Code: Alles auswählen

destructor TMyClass.Destroy;
begin
  inherited Destroy();
end;
Oder ist das nur bei bestimmten Aufrufen nötig?

Viele Grüße,
Kay
Zuletzt geändert von Lori am Mo 10. Dez 2012, 21:57, insgesamt 1-mal geändert.
Grund: Bitte den richtigen Highlighter verwenden!

Benutzeravatar
theo
Beiträge: 11383
Registriert: Mo 11. Sep 2006, 19:01

Re: Implementierung einer rekursiven Funktion

Beitrag von theo »

Das ist eine gute Frage, auf die ich die Antwort auch nicht genau weiss.

Das ganze "Durcheinander" kommt wahrscheinlich daher, dass der Funktionsname innerhalb der Fkt. auch ein Synonym für "Result" ist.

Das

Code: Alles auswählen

function Apfel:String;
begin
  Apfel:='Boskoop';
  ShowMessage(Apfel);
end;
Tut das gleiche wie das

Code: Alles auswählen

function Apfel:String;
begin
  Result:='Boskoop';
  ShowMessage(Result);
end;    
Daher hat der Compiler ohne die Klammern wohl Mühe zu kapieren, dass du einen Funktionsaufruf meinst.

Bin für eine schlauere Erklärung auch dankbar.

Kay
Beiträge: 134
Registriert: So 14. Nov 2010, 15:17

Re: Implementierung einer rekursiven Funktion

Beitrag von Kay »

OK, das würde den Effekt erklären.
Naja, auf jeden Fall funktioniert's jetzt erstmal, vielen Dank nochmal für den Tipp.

Viele Grüße,
Kay

Antworten