title: Erlang, Last Call Optimization, lambda functions, and how to prevent growing a stack
body: <p>I'm writing some Erlang code, and I've run into a bizarre situation that I don't understand.</p>
  
  <p>The code:</p>
  
  <pre><code>-module(recursive_test).
  -export([a/2]).
  
  a(_, []) -&gt; ok;
  a(Args, [H|T]) -&gt;
      F = fun() -&gt; a(Args, T) end,
      io:fwrite(
          "~nH: ~p~nStack Layers: ~p",
          [H, process_info(self(), stack_size)]
      ),
      b(Args, F).
  
  b(Args, F) -&gt;
      case Args of
          true -&gt; ok;
          false -&gt; F()
      end.
  </code></pre>
  
  <p>The output:</p>
  
  <pre><code>(Erlang/OTP 20)
  12&gt; c(recursive_test).
  {ok,recursive_test}
  13&gt; recursive_test:a(false, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).
  H: 1
  Stack Layers: 28
  H: 2
  Stack Layers: 28
  H: 3
  Stack Layers: 28
  H: 4
  Stack Layers: 28
  H: 5
  Stack Layers: 28
  H: 6
  Stack Layers: 28
  H: 7
  Stack Layers: 28
  H: 8
  Stack Layers: 28
  H: 9
  Stack Layers: 28
  H: 10
  Stack Layers: 28
  ok
  14&gt; recursive_test:a(false, [1, 2, 3, 4, 5, 6]).
  H: 1
  Stack Layers: 28
  H: 2
  Stack Layers: 28
  H: 3
  Stack Layers: 28
  H: 4
  Stack Layers: 28
  H: 5
  Stack Layers: 28
  H: 6
  Stack Layers: 28
  ok
  </code></pre>
  
  <p>From what I understand from <a href="http://erlang.org/pipermail/erlang-questions/2016-October/090663.html" rel="nofollow noreferrer">this article</a>, Erlang uses a Last Call Optimization where, if the last thing a function does is to call another function, the BeamVM will instead jump the program counter to the start of the new function instead of pushing a new stack frame. Does this mean that in a pattern like the above, we're stomping around the heap instead of around the stack? Does this free the memory that was previously held in these functions (in the case of the above code, would we have <em>one</em> copy of function F allocated in memory at a time, or would we have <em>many</em> copies of the function F allocated in memory at a time)? Are there any negative consequences to using this pattern (other than the obvious debugging struggle)?</p>