再帰! スタック! ローカライズ!
とまあ、軽いジョークはおいといて。
恐るべき現実(マイナー言語によるFizzBuzz問題解集) - 永字八法
>なお、NScripterでは再帰はかなりきつい
こんなことを言われると、つい再帰を使いたくなるひねくれ者が来ました(笑)
そんな訳でNScripterで再帰でFizzBuzzを書いてみましたけど、
FizzBuzz本体より、再帰に必要な土台の方が長い……
http://bugyo.tk/~zick/fizzbuzz.txt
全くこんなことをされると寝る時間が減るじゃないか本当に。と筋違いの文句を言ってみる。
NScripterで、本格的に再帰ができないかどうかを確かめてみる。
そこで、とりあえず動くと言うレベルで組んでみたので、検証のためUPしてみる。
参考にしたのはもちろん、http://bugyo.tk/~zick/fizzbuzz.txtである。
再帰のサンプル。フィボナッチ数列を再帰で計算する。
*define caption "フィボナッチ数列によるスタック実験" mov %0,100 numalias stack_num,%0:inc %0 numalias stack_cursor_num,%0:inc %0 numalias stack_cursor_str,%0:inc %0 numalias STACK_START,1000 numalias STACK_END,4096 defsub push defsub pop defsub push2 defsub pop2 defsub stack_init numalias fibonacci_result,%0:inc %0 numalias fibonacci_loop,%0:inc %0 numalias fibonacci_n,%0:inc %0 numalias fibonacci_n1,%0:inc %0 numalias fibonacci_n2,%0:inc %0 numalias fibonacci_n3,%0:inc %0 defsub fibonacci1 defsub fibonacci2 game *fibonacci1 getparam i%fibonacci_result,%fibonacci_n if %fibonacci_n<1 itoa $fibonacci_n,%fibonacci_n:add $fibonacci_n,"はnの数値として不適当です。":mesbox $fibonacci_n,"error!":end if %fibonacci_n<3 mov %%fibonacci_result,1:return mov %fibonacci_n1,1 mov %fibonacci_n2,1 for %fibonacci_loop=3 to %fibonacci_n mov %fibonacci_n3,%fibonacci_n1+%fibonacci_n2 mov %fibonacci_n1,%fibonacci_n2 mov %fibonacci_n2,%fibonacci_n3 next mov %%fibonacci_result,%fibonacci_n2 return *fibonacci2 push %fibonacci_n push %fibonacci_n1 push %fibonacci_n2 getparam i%fibonacci_result,%fibonacci_n if %fibonacci_n<1 itoa $fibonacci_n,%fibonacci_n:add $fibonacci_n,"はnの数値として不適当です。":mesbox $fibonacci_n,"error!":end mov %fibonacci_n1,0 mov %fibonacci_n2,0 if %fibonacci_n<3 mov %%fibonacci_result,1:jumpf fibonacci2 %%fibonacci_result,%fibonacci_n-2 mov %fibonacci_n1,%%fibonacci_result fibonacci2 %%fibonacci_result,%fibonacci_n-1 mov %fibonacci_n2,%%fibonacci_result mov %%fibonacci_result,%fibonacci_n1+%fibonacci_n2 ~ pop %fibonacci_n2 pop %fibonacci_n1 pop %fibonacci_n return *stack_init mov %stack_cursor_num,STACK_START mov %stack_cursor_str,STACK_START return *push if %stack_cursor_num>STACK_END mesbox "stack overflow.","error!":end getparam i%stack_num mov %%stack_cursor_num,%%stack_num inc %stack_cursor_num return *pop notif %stack_cursor_num>STACK_START mesbox "stack underflow.","error!":end getparam i%stack_num dec %stack_cursor_num mov %%stack_num,%%stack_cursor_num return *push2 if %stack_cursor_str>STACK_END mesbox "stack overflow.","error!":end getparam s%stack_num mov $%stack_cursor_str,$%stack_num inc %stack_cursor_str return *pop2 notif %stack_cursor_str>STACK_START mesbox "stack underflow.","error!":end getparam s%stack_num dec %stack_cursor_str mov $%stack_num,$%stack_cursor_str return *start saveoff stack_init for %0=1 to 15 fibonacci2 %1,%0 第%0項は%1 next click end
解説
フィボナッチ数列を計算するのに、二つ(内部的には三つ)の命令を自作した。
どちらも二つの引数を取り、第一引数は結果を受け取る変数、第二引数はフィボナッチ数列の項数を指定する。
fibonacci1 a(n),n
こんな風な指定の仕方をする訳だ。
※スクリプトを置き換えました。
- fibonacci1
- 再帰とか使わないでフラットに計算する。素直に組んで見た例で、何も問題はない。ただし、n=1から馬鹿正直に計算するので当然ながらnが大きくなればなるほど実行時間はかかる。
- fibonacci2
- 再帰を使って計算するバージョン。
内部的にはfibonacci3を呼び出してるだけ。そしてfibonacci1よりも時間がかかるのは分かりきってることだが。
:fibonacci3:fibonacci2の中で使われているいわゆる本体。自分を呼び出す再帰構造を持っている。
fibonacci2とfibonacci3の関係が、なんだかPrologの再帰定義を彷彿とさせるな。つまりこれが、当然の帰結なんだろうか。