Даже ваша правка не хвостовая рекурсия:
loop() ->
receive
{sys, Msg} ->
handle_sys_msg(Msg),
loop();
{From, Msg} ->
Reply = handle_msg(Msg),
From ! Reply,
loop();
_ -> continue
end,
loop().
Порядок выполнения для одной функции: receive ... end, loop()
.Теперь, если вы получите сообщение {sys, _}
, из получателя будет вызван loop/0
, преобразующий вышеприведенный порядок выполнения во что-то эквивалентное:
loop() ->
receive
loop() ->
receive
...
end,
loop(),
end,
loop() ->
...
Проблема в том, что если вы вызываете loop()
изнутри приема, виртуальная машина все еще должна сохранять точку возврата, чтобы запустить loop()
на месте после receive
.
Чтобы сделать вашу функцию хвостовой рекурсивной, вам необходимовыполните:
loop() ->
receive
{sys, Msg} ->
handle_sys_msg(Msg);
{From, Msg} ->
Reply = handle_msg(Msg),
From ! Reply;
_ -> continue
end,
loop().
или
loop() ->
receive
{sys, Msg} ->
handle_sys_msg(Msg),
loop();
{From, Msg} ->
Reply = handle_msg(Msg),
From ! Reply,
loop();
_ -> loop()
end.
Где вызов loop()
действительно всегда - последнее, что нужно сделать в функции.