再帰の中のResultの取得の方法するには?


YouE  2009-07-04 11:08:59  No: 35036

再帰の中に、Resultがあると、再帰の分だけ、Resultが返るんですか?

function TForm1.Reflexive(var a : Integer): String;
var
  i : Integer;
begin
{1}  a := a +1;

{2}  if a < 10 then Reflexive(a);

{3}  a := a +3;

{4}  Result := IntToStr(a);
{5}  Memo1.Lines.Add('★' +  IntToStr(a));
end;

こいつを呼び出すと、
★13★16★19★22★25★28★31★34★37★40
となり、最終的な戻り値が  40  になるのは、なんででしょうか?
{2}で再帰で、止まりますよね?
{2}の条件を抜けた時に、{3}から再帰の数だけ、繰り返されるんですよね?
なんか、無駄な気がするんですが、必要な場合もあるのか。

いや、再帰の中で、Resultが必要で、どうも求めているのと違うと思ったら、{5}が繰り返されていた、始めて気が付きました。

で、本題なのですが、これの戻り値を、最初の13にするにはどうしたらいいのでしょうか?
そもそも書き方が、間違っているのでしょうか?

よろしく御願い致します。


tor  2009-07-04 11:46:22  No: 35037

> 再帰の中に、Resultがあると、再帰の分だけ、Resultが返るんですか?
単にaの値をResultに入れてるから、
aの最終的な値が関数値になってるだけでしょう。

> 再帰で、止まりますよね?
関数なんですから、終わったら呼び出し元に戻ってきます。

Reflexive(1)
  {1}をやる
  Reflexive(2)を呼ぶ
    {1}をやる
    Reflexive(3)を呼ぶ
      ……
      Reflective(9)を呼ぶ
        {1}をやる
        (a=10になったので再帰終わり)
        {3}{4}{5}をやる
      Reflective(9)から戻ってくる
      {3}{4}{5}をやる
      ……
    Reflective(3)から戻ってくる
    {3}{4}{5}をやる
  Reflective(2)から戻ってくる
  {3}{4}{5}をやる
Reflective(1)から戻る

いったい何を目的にした関数なのかさっぱりわかりませんが、
> これの戻り値を、最初の13にするにはどうしたらいいのでしょうか?
と言うなら
if a < 10 then
  Result := Reflexive(a)
else
  begin a := a + 3; Result := IntToStr(a + 3); end;
とでもすればいいのでは。


YouE  2009-07-04 18:24:10  No: 35038

再帰を抜ける時は、Resultの内容が消えるんですね。
スコープってヤツか。
そうなると、最初のResultの値を、最後まで保持するには、グローバル変数か、引数にして引き渡すしかないか。


DEKO  2009-07-04 21:24:58  No: 35039

> 最初のResultの値
一番深い再帰の時のaの値を文字列として戻り値にしたいのであれば
torさんのコードがそれを実現しています。

>再帰を抜ける時は、Resultの内容が消えるんですね。
"戻り値が有効に使われていない" というのが正しいかもしれません。
ですから、'13' を得るだけだったら

function TForm1.Reflexive(var a : Integer): String;
var
  v: Integer;
  procedure _Reflexive(var a : Integer);
  begin
    a := a + 1;
    if a < 10 then 
      _Reflexive(a)
    else  
      a := a + 3;
  end;
begin
  v := 0;
  _Reflexive(v);
  result := v;
end;

このように再帰は関数でなく手続きでいい事になります。

再帰は主に値を列挙する用途に使います。
列挙を伴わないで条件になるまで繰り返して単一の値を得たいのであれば、

function TForm1.Reflexive(a : Integer): String;
var
  i: Integer;
begin
  i := a;
  repeat
    i := i + 1;
  until (i = 10);
  result := IntToStr(i + 3);
end;

このように再帰ではなくループで処理可能です。

# "再帰でなければならない理由" を書いて頂けると、
# YouEさんの 意に沿ったレスが付くと思います。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加