ラムダは究極のgoto

ラムダとgotoの区別がつかなくなってきた。

#include <stdio.h>

int main(void)
{
    int i = 10;
    int n;
    int acc;

loop:
    if (i == 0)
        goto end;
    else {
        #define loop_dec_cont loop
        #define display_cont loop_dec
        #define fact_cont display
        n = i;
        acc = 1;
        goto fact;
    }

loop_dec:
    i = i - 1;
    goto loop_dec_cont;

display:
    printf("fact %d : %d\n", i, acc);
    goto display_cont;

fact:
    if (n == 0)
        goto fact_cont;
    else {
        acc *= n;
        n = n - 1;
        goto fact;
    }

end:
    return 0;
}

うぅん。うまく書けない。

ジャンプしてるんじゃないんだ。gotoの先に展開される感じなんだよ。


TCCのソースを読むと、あたかもそこに関数があるかのように自然にgotoが使われてる。感動した。


ラムダは究極のgotoであると言えるかもしれない。

うまく書けない理由

そうだ。Cのgotoだけではうまく書けない理由がわかった。

「Cにはpusha,popaがない」

pusha,popaはアセンブリ命令で汎用レジスタの内容を全て保存する命令。pushaで前に作業してた環境を保存しておいて、popaで元の環境に戻す。残念ながらCには無い命令。


Cは、call > pusha > 関数の実行 > popa > ret。関数呼んだら、関数を呼んだところに戻る。


継続は、pusha > jmp > 関数の実行 > popa > jmpで、関数呼んでも、呼んだ先には戻らずそのまま継続していく。


呼んだ先には戻らず。というのがうまく書けないし、環境の保存も出来ない。


しかし、ジャンプしたり、環境を保存したりして、基本的な考え方自体はあんまり変わらないのかも。