2013-07-09 3 views
7

가 나는이 부분을 이해하지 못하는 http://learnyousomeerlang.com/errors-and-exceptionstry catch 블록에 tail 재귀 코드가 없습니까?

에서 얼랑 교훈을 읽고있다 :

익스프레션 시도 사이의에하는 것은 보호 할 수 있다고한다. 즉, 해당 호출 내에서 발생하는 모든 종류의 예외가 잡히게됩니다.

그리고

예외의 보호 된 부분은 꼬리 재귀가 될 수 없습니다. 의와 캐치 사이에 재귀 호출을 둬서

[...]

, 당신은 보호 된 부분에없는 당신은 마지막 통화 최적화 도움이됩니다.

따라서 예외가 발생하는 부분에는 재귀 호출을 넣을 수 없습니까? 그러면 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). 

그는 우리가 함수에 꼬리 재귀 코드를 래핑하는 함수를 사용할 필요가 있음을 의미 하는가 우리가 시험 잡을 때 보호받는 부분에있을 때?

답변

11

따라서 예외가있는 부분에 이 걸리는 부분에는 재귀 호출을 넣을 수 없습니까? 그러면 try catch 블록의 핵심은 무엇입니까?

함수는 try 내부에서 재귀 적으로 호출 할 수 없습니다. 또는 오히려 테일 최적화가 발생하지 않습니다. try을 사용할 때 호출 스택 아래 어느 지점에서든지 catch 블록으로 돌아갈 수 있어야합니다. 즉, 이되어야 호출 스택이이됩니다. 꼬리 호출 최적화가 사용되는 경우 함수 호출은 이제 막 루프이므로 루프가 필요하지 않습니다. 다시 돌아갈 수는 없습니다. 따라서 try 블록 내부의 재귀가 실제로 재연되어야합니다.

대부분의 언어에서 예외와 동일합니다. 그는 우리에 꼬리 재귀 코드를 래핑하는 함수를 사용할 필요가 있음을 뜻

: 때문에, 예외 처리의 유틸리티를 제거하지 않습니다 확실히 직접 같이 Recurse 성가심의 약간이지만, 할 수 있다는 사실 우리가 try catch의 보호 된 부분에있을 때의 함수 ?

예. 필요한 것은 하나의 추가 기능 뿐이며 try을 사용하면 TCO의 이점을 얻을 수 있습니다. 예 :

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

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

helper() -> helper(). 

난 당신이 총 소유 비용 (TCO)이 일어날 것으로 예상 할 때 실수로 재귀하고 있는지 확인하는 쉬운 방법이 있는지 확실하지 않습니다.너 try을 사용할 때 아마 방심하지 않아도됩니다.

0

tail-call을 최적화하려면 해당 호출이 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]). 
관련 문제