Sean Eshbaugh

Web Developer + Programmer

Recursive Closures in Elixir

File this under "things that are obvious in retrospect". I got to wondering if it's possible to recursively call a closure in Elixir. The answer is of course, yes, but with a small caveat. You simply have to pass the function (so it can't be truly anonymous) as an argument so it can be used as a callback.

Consider the following pathetic first attempt:

lol = fn
  0 -> 0
  x -> x + lol.(x - 1)
end

IO.puts lol.(100)

Looks good, right? Not quite...

seshbaugh ~% elixir lol.exs
** (CompileError) /Users/seshbaugh/lol.exs:3: function lol/0 undefined
    src/elixir_translator.erl:463: :elixir_translator.translate_each/2
    src/elixir_translator.erl:613: :elixir_translator.translate_arg/2
    lists.erl:1339: :lists.mapfoldl/3
    lists.erl:1340: :lists.mapfoldl/3
    src/elixir_translator.erl:620: :elixir_translator.translate_args/2
    src/elixir_translator.erl:80: :elixir_translator.translate_each/2
    lists.erl:1339: :lists.mapfoldl/3

The closure has no idea what we're talking about. Which shouldn't really come as a surprise, we're still in the middle of defining the value of lol (that's my understanding as of right now, if I discover that I'm right for the wrong reason I will be sure to update this post). If we want to call lol from within itself we have to pass a reference to it to itself, like so:

lol = fn
  _, 0 -> 0
  lol, x -> x + lol.(lol, x - 1)
end

IO.puts lol.(lol, 100)

This time around we pass lol has an argument to itself. In the first function clause the callback is ignored (since its purpose is to halt the recursion) and in the second one we use call it, with itself as the first argument again. Now when we run this we get the expected output:

seshbaugh ~% elixir lol.exs
5050

I'm not sure if this is really all that useful, since you could (and probably should) use defp in your modules to define private functions that aren't available outside the module. But it never hurts to know what's possible!