わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

再帰でカウントダウン,カウントアップ

こちらで挙げた課題を順にコードにされていて,嬉しいのですが,再帰メソッドでカウントダウン・カウントアップがこちらの意図と違っており,ちょっと悲しいです.
用意していた答えは以下のとおり.

def countdown(n)
  return if n < 0
  puts n
  countdown(n - 1)
end

def countup(n)
  return if n < 0
  countup(n - 1)
  puts n
end

動作を解説していきます.
例えば,countdown(5)という式でメソッドを呼び出すと,"5"の出力,countdown(4)の呼び出し,"4"の出力,countdown(3)の呼び出し,…,"0"の出力,countdown(-1)の呼び出しとなって,n=-1のときにはif文が真になるのでそこでcountdown(-1)の処理は終了し,呼び出し元に戻ります.
どこに戻るのかというと*1,countdown(0)の処理中,「countdown(-1)」の呼び出しをした直後です.直後といっても,処理はありませんから,ここでcountdown(0)もおしまい.あとは,逆順に戻って,countdown(5)の処理まで終了し,呼び出し元に戻るということです.
一方,countup(5)という式でメソッドを呼び出すと,countup(4)の呼び出し,countup(3)の呼び出し,…,countup(-1)の呼び出しまで,「puts n」のところを実行することなく,再帰呼び出しをしていきます.
countup(-1)の処理で,if文が真になるのでそこでcountup(-1)の処理は終了.呼び出し元に戻るのですが,どこかというと,countup(0)の処理中,「countup(-1)」の呼び出しをした直後です.直後というと,「puts n」があります.n=0ですので,ここで"0"の出力となります.以後,countup(0)の終了,"1"の出力,countup(1)の終了,…,"5"の出力,countup(5)の終了の順に処理して,呼び出し元に戻ります.
以上を「〜の出力」に着目して見直すと,countdownは確かにカウントダウンに,countupは確かにカウントアップになっていますね.
Rubyで書きましたが,Cでも同様に関数が定義できますし,最近のプログラミング言語では同様のものが書けるでしょう.
書ける条件としては,仮引数となる変数が,関数呼び出しごとに作られること.これにより,countdown(5)における変数nと,countdown(4)における変数nが,異なる実体としてメモリ内に確保されます.これが,変数への代入式・代入文なしで面白い関数を書ける理由であるとともに,再帰がメモリをよく食う理由でもあるわけです.