try catch块中没有尾递归代码?

Sim*_*mon 10 erlang

我正在http://learnyousomeerlang.com/errors-and-exceptions上阅读Erlang课程

我不明白这一部分:

据说try和of之间的表达受到保护.这意味着将捕获该调用中发生的任何类型的异常.

异常的受保护部分不能是尾递归.

[...]

通过在of和catch之间进行递归调用,您不在受保护的部分中,并且您将受益于Last Call Optimization.

所以我们不能在捕获异常的部分放置递归调用?那么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).
Run Code Online (Sandbox Code Playgroud)

他是否意味着当我们处于try catch的受保护部分时,我们需要使用函数将尾递归代码包装到函数中?

Chr*_*ris 14

所以我们不能在捕获异常的部分放置递归调用?那么try catch块有什么意义呢?

函数不能递归调用自身内部try; 或者说,如果确实如此,尾部优化将不会发生.使用时try,您必须能够catch在调用堆栈的任何位置跳回到块.这也就意味着,有有一个调用堆栈.如果使用尾调用优化,则没有函数调用,因为它们现在只是循环.什么都没有跳回去.因此,try块内的递归必须真正递归.

这一点与大多数语言中的例外情况相同.您不能直接递归的事实有点令人烦恼,但肯定不会删除异常处理的效用,因为:

他是否意味着当我们处于try catch的受保护部分时,我们需要使用函数将尾递归代码包装到函数中?

是.所需要的只是一个额外的功能,您可以使用try得很好,仍然可以获得TCO的好处.例:

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

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

helper() -> helper().
Run Code Online (Sandbox Code Playgroud)

我不确定是否有一种简单的方法可以确定在您预期TCO发生时是否意外复发.你可能只需要在使用时保持警惕try.