接收块中的尾递归
Tail recursion in a receive block
我看到包含接收块的函数被递归调用,似乎不在 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
是否接收到一个特殊的构造,可以优化所有匹配块末尾的尾部位置?如果是这样,如果接收块有一个 after
块,它是否适用?如果函数中接收块后面有代码怎么办?
在您的示例中,只有最后一次调用 loop
是尾递归的。不要在 receive
块内进行递归调用,只需让 receive
return 并使用尾递归调用在已经存在的函数末尾循环。
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
作为一般规则,进程循环应该总是在 loop
函数的末尾有一个递归调用。这是保证进程能够无限循环的最简单方法。
但是,如果 receive
块是 loop
函数中的最后一条语句,您 可以 在 receive
块内循环。结果也将是尾递归的。这允许您根据收到的消息有条件地停止循环
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
另见 http://erlang.org/doc/efficiency_guide/processes.html#id69762
我看到包含接收块的函数被递归调用,似乎不在 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
是否接收到一个特殊的构造,可以优化所有匹配块末尾的尾部位置?如果是这样,如果接收块有一个 after
块,它是否适用?如果函数中接收块后面有代码怎么办?
在您的示例中,只有最后一次调用 loop
是尾递归的。不要在 receive
块内进行递归调用,只需让 receive
return 并使用尾递归调用在已经存在的函数末尾循环。
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
作为一般规则,进程循环应该总是在 loop
函数的末尾有一个递归调用。这是保证进程能够无限循环的最简单方法。
但是,如果 receive
块是 loop
函数中的最后一条语句,您 可以 在 receive
块内循环。结果也将是尾递归的。这允许您根据收到的消息有条件地停止循环
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
另见 http://erlang.org/doc/efficiency_guide/processes.html#id69762