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

Erlang try-catch块中没有尾部递归代码?,erlang,Erlang,我正在学校读二郎课 我不明白这部分: 介于try和of之间的表达式被称为受保护。这意味着该调用中发生的任何类型的异常都将被捕获 及 异常的受保护部分不能是尾部递归的 [……] 通过将递归调用放在of和catch之间,您就不在受保护的部分,您将从上次调用优化中受益 所以我们不能把递归调用放在捕获异常的部分?那么试一试又有什么意义呢 在下面的页面中,我们有一个例子,在受保护的部分有一个尾部递归函数 has_value(Val, Tree) -> try has_value1(Val, Tr

我正在学校读二郎课

我不明白这部分:

介于try和of之间的表达式被称为受保护。这意味着该调用中发生的任何类型的异常都将被捕获

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

[……]

通过将递归调用放在of和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的受保护部分时,我们需要使用一个函数将尾部递归代码包装到一个函数中吗

因此,我们不能将递归调用放在异常所在的部分 被抓住了?那么试一试又有什么意义呢

函数不能在
try
中递归调用自身;或者更确切地说,尾部优化不会发生。使用
try
时,必须能够在调用堆栈的任何点跳回
catch
块。这意味着必须有一个调用堆栈。如果使用尾部调用优化,就不会有函数调用,因为它们现在只是循环。没有什么好回头的。因此
try
块内部的递归必须真正递归

这一点与大多数语言中的异常相同。您不能直接递归这一事实有点麻烦,但肯定不会删除异常处理的实用程序,因为:

他是说我们需要使用一个函数来包装尾部递归吗 当我们处于try-catch的受保护部分时,将代码编码到函数中 ?

对。它只需要一个额外的功能,您就可以使用
试试
很好,并且仍然可以获得TCO的好处。例如:

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

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

helper() -> helper().

我不确定是否有一种简单的方法来确定当您期望TCO发生时是否意外地递归。在使用
try

时,您可能需要保持警惕。如果您希望优化尾部调用,则该调用必须在try-catching子句之外。你可以使用构造

your_fun(...) ->
   ...
   try ... of               <--- make notice of `of`
      ... ->
         some_call(...)
   catch
      ...
   end.
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]).