接收块中的尾递归

gre*_*reg 1 tail-recursion elixir

我看到包含一个接收块的函数被递归调用,似乎不是在elixir示例代码中的所有位置的尾部位置.例如:

defmodule A do
  def loop do
    receive do
      :ping ->
         IO.puts "Received :ping"
         loop # <- Tail position?
      :pong ->
         IO.puts "Received :pong"
         loop # <- Also Tail position?
      after
        5000 ->
          loop # <- Also Tail position?
     end
     loop # <- Also Tail position?
  end
end
Run Code Online (Sandbox Code Playgroud)

是否会收到一个特殊的构造,在所有匹配块的末尾优化尾部位置?如果接收块有after块,它是否适用?如果函数中的接收块之后有代码怎么办?

Pat*_*ity 5

在您的示例中,只有最后一次调用loop是尾递归.不要在receive块内部进行递归调用,只需让receive返回并使用尾递归调用在已经存在的函数的末尾循环.

defmodule A do
  def loop do
    receive do
      :ping ->
         IO.puts "Received :ping"
      :pong ->
         IO.puts "Received :pong"
      after
        5000 ->
          nil
     end
     loop
  end
end
Run Code Online (Sandbox Code Playgroud)

作为一般规则,进程循环应始终在loop函数末尾只有一个递归调用.这是保证流程能够无限循环的最简单方法.

但是,如果它是函数中的最后一个语句,则可以receive块内循环loop.结果也将是尾递归.这允许您根据收到的消息有条件地停止循环

defmodule A do
  def loop do
    receive do
      :ping ->
         IO.puts "Received :ping"
         loop
      :pong ->
         IO.puts "Received :pong"
         loop
      :stop ->
         IO.puts "Bye Bye"
     end
  end
end
Run Code Online (Sandbox Code Playgroud)

另请参阅http://erlang.org/doc/efficiency_guide/processes.html#id69762