末尾再帰

なんか関数の最後で再帰呼び出しすると勝手にループになるらしいですよ。まぁ適当にデクリメントしながら画面に表示する関数を書く。

let rec print_decrement x =
  if x = 0 then
    ()
  else (
    print_int x;
    print_decrement (x-1);
   )

let _ =
  print_decrement 100000;
  print_newline ();

ここでポイントは else の後に ( を書くと手続き脳の世界に行けるというこないだ教えてもらったことなのですがそれはともかく。

080497b0 <camlTail__print_decrement_57>:
 80497b0:       83 ec 04                sub    $0x4,%esp
 80497b3:       83 f8 01                cmp    $0x1,%eax
 80497b6:       75 18                   jne    80497d0 <camlTail__print_decremen
t_57+0x20>
 80497b8:       b8 01 00 00 00          mov    $0x1,%eax
 80497bd:       83 c4 04                add    $0x4,%esp
 80497c0:       c3                      ret
 80497c1:       eb 0d                   jmp    80497d0 <camlTail__print_decremen
t_57+0x20>
 80497c3:       90                      nop
 80497c4:       90                      nop
 80497c5:       90                      nop
 80497c6:       90                      nop
 80497c7:       90                      nop
 80497c8:       90                      nop
 80497c9:       90                      nop
 80497ca:       90                      nop
 80497cb:       90                      nop
 80497cc:       90                      nop
 80497cd:       90                      nop
 80497ce:       90                      nop
 80497cf:       90                      nop
 80497d0:       89 04 24                mov    %eax,(%esp)
 80497d3:       e8 28 07 00 00          call   8049f00 <camlPervasives__string_o
f_int_153>
 80497d8:       89 c3                   mov    %eax,%ebx
 80497da:       a1 18 a6 05 08          mov    0x805a618,%eax
 80497df:       e8 9c 08 00 00          call   804a080 <camlPervasives__output_s
tring_214>
 80497e4:       8b 04 24                mov    (%esp),%eax
 80497e7:       83 c0 fe                add    $0xfffffffe,%eax
 80497ea:       eb c7                   jmp    80497b3 <camlTail__print_decremen
t_57+0x3>
 80497ec:       8d 74 26 00             lea    0x0(%esi),%esi

んーなんでそんな nop はさまってるねんと思いつつも、まぁ call print_decrement みたいなのが無いのは確認できますねーよかたですねー。んで print_decrement => print_int と呼び出し順を変えてやると、

 80497d6:       e8 d5 ff ff ff          call   80497b0 <camlTail__print_decrement_57>

とかが現れやがりまして、ああなるほど再帰しちゃってるのうと。実際実行してやるとスタックオーバーフローするわけですよ。

でもですね。ぶっちゃけ末尾かどうかなんて気にするのめんどいのでなんかどうでもいいというかですね。私はシグナルハンドラの中でなんでもやっちゃいたい人なんですよとかそういう話。

そんなこと気にしてたら LL の舞台には上がれませんよ。ていうか OCaml はどう見ても LL じゃないと思います。だって print_string とか print_int とか + とか +. とか .() とか .[] とかなんか気軽感がどこにもないですよ。あえて言うなら型書かなくていいという話ですけど、それなら C も LL ですな。

あ、ちなみに 新しい言語を学ぶときはアセンブリを出力しなさいというお告げ があったのでなんとなく objdump したとかそういう複雑な経緯がありまして。

なにかあれば下記メールアドレスへ。
shinichiro.hamaji _at_ gmail.com
shinichiro.h