0

factorial のような関数を書く場合:

fac(Val) when is_integer(Val)->
    Visit = fun (X, _F) when X < 2 -> 
                    1;
                (X, F) ->
                    X * F(X -1, F)
            end,
    Visit(Val, Visit).

テール コールの最適化は単純ではありませんが、継続解析スタイルで記述すると次のようになります。

fac_cps(Val) when is_integer(Val)->
    Visit = fun (X, _F, K) when X < 2 -> 
                    K (1);
                (X, F, K) ->
                    F(X-1, F, fun (Y) -> K(X * Y) end)
            end,
    Visit(Val, Visit, fun (X) -> X end).

または、おそらく非機能化されたもの:

fac_cps_def_lambdas({lam0}, X) ->
    X;
fac_cps_def_lambdas({lam1, X, K}, Y) ->
    fac_cps_def_lambdas(K, X*Y).


fac_cps_def(X) when is_integer(X) ->
    fac_cps_def(X, {lam0}).

fac_cps_def(X, K) when X < 2 -> 
    fac_cps_def_lambdas(K,1);
fac_cps_def(X, K) ->
    fac_cps_def(X-1, {lam1, X, K}).

これら 3 つの実装のタイミングを計ると、実行時間は予想どおり同じであることがわかりました。

私の質問は、これよりも詳細な知識を得る方法はありますか? たとえば、関数を実行する際のメモリ使用量を取得するにはどうすればよいですか?スタック メモリをまったく使用しないようにしていますか?

この種のものを検査するための標準的なツールは何ですか?

質問は、関数のスタックの高さをどのように測定するか、それぞれの関数呼び出しのメモリ使用量をどのように判断するか、そして最後にどれが最適かということです。

4

2 に答える 2

3

私の解決策は、コードを目で検査することです。時間の経過とともに、コードが末尾呼び出しスタイルであるかどうかを見つける方法を学びます。通常、そのコードを通過する構造のサイズが巨大であることがわかっていない限り、あまり気にしません。

それは私の直感によるものです。でプロセスのスタックサイズを調べることができerlang:process_info/2ます。でランタイムを調べることができfprofます。しかし、私は最後の手段としてのみ修正します。

于 2013-05-27T09:21:19.797 に答える