2013-07-09 29 views
7

私はこの部分を理解していないhttp://learnyousomeerlang.com/errors-and-exceptionstry catchブロックにテール再帰コードはありませんか?

でErlangのレッスンを読んでいます:

試し間の中での発現が保護されると言われています。これは、その呼び出し内で起こっているあらゆる種類の例外がキャッチされることを意味します。

そして

例外の保護された部分は、末尾再帰にすることはできません。

[...]

のとキャッチの間に、あなたの再帰呼び出しを置くことによって、あなたは保護された部分ではありません、あなたは最後の呼び出しの最適化の恩恵を受ける。

したがって、例外がキャッチされた部分に再帰呼び出しを入れることはできませんか? try catchブロックのポイントは何ですか?

私たちが保護されたセクションの末尾再帰関数との例を持っているページで

以下...

has_value(Val, Tree) -> 
    try has_value1(Val, Tree) of 
    false -> false 
    catch 
    true -> true 
    end. 

has_value1(_, {node, 'nil'}) -> 
    false; 
has_value1(Val, {node, {_, Val, _, _}}) -> 
    throw(true); 
has_value1(Val, {node, {_, _, Left, Right}}) -> 
    has_value1(Val, Left), 
    has_value1(Val, Right). 

彼は我々が関数に末尾再帰のコードをラップする機能を使用する必要があることを意味しています私たちがtry catchの保護された部分にいるときは?

答えて

11

したがって、例外が発生した部分には再帰呼び出しを挿入できません。 はキャッチしましたか? try catchブロックのポイントは何ですか?

関数は、再帰的に自身をtryの内部で呼び出すことはできません。そうであれば、テールの最適化は起こりません。 tryを使用するときは、コールスタックの任意のポイントでcatchブロックに戻ることができなければなりません。つまり、にはコールスタックが必要です。テールコールの最適化が使用されている場合、関数呼び出しは今は単なるループなので、関数呼び出しはありません。戻ってくるものは何もない。したがって、tryブロック内の再帰が本当に繰り返されなければなりません。

ほとんどの言語の例外と同じです。彼は私達がに末尾再帰 コードをラップする機能を使用する必要があることを意味してい

:あなたは直接再帰迷惑のビットであることはできませんが、ので、確かに、例外処理のユーティリティを削除していないという事実私たちがtry catchの保護された部分にいるときの関数 ?

はい。それに必要なのは1つの余分な機能で、tryを使っても問題ありませんが、TCOのメリットがあります。例:

% No TCO 
func() -> 
    try 
    func() 
    catch _ -> 
    ok 
    end. 

% TCO 
func() -> 
    try 
    helper() 
    catch _ -> 
    ok 
    end. 

helper() -> helper(). 

私はあなたがTCOが起こることを期待していたときに誤って再帰しているかどうかを判断する簡単な方法があるかどうかわかりません。tryを使用しているときは、おそらく警戒する必要があります。

0

テールコールを最適化するには、その呼び出しがtry-catching句の外にある必要があります。あなたは工事を使用することができます

your_fun(...) -> 
    ... 
    try ... of    <--- make notice of `of` 
     ... -> 
     some_call(...) 
    catch 
     ... 
    end. 

または単にtry節の後にその呼び出しを行うことができます。

has_value1(Val, Right).というコードでは、関数内の最後の呼び出しであるため、最適化されています。この場合はtryブロックと呼ばれても問題ありません。例外は、この関数から早期に終了し、結果を簡単に処理するためにのみ使用されます。

それは例外なしに書き換えられますが、マニュアルのスタック処理を使用することができます

has_value(Val, Tree) -> 
    has_value(Val, [Tree]). 

has_value1(_, []) -> 
    false; 
has_value1(Val, [{node, 'nil'} | Stack]) -> 
    has_value1(Val, Stack); 
has_value1(Val, [{node, {_, Val, _, _}} | _]) -> 
    true; 
has_value1(Val, [{node, {_, _, Left, Right}} | Stack]) -> 
    has_value1(Val, [Left, Right | Stack]). 
関連する問題