なんか関数の最後で再帰呼び出しすると勝手にループになるらしいですよ。まぁ適当にデクリメントしながら画面に表示する関数を書く。
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 したとかそういう複雑な経緯がありまして。