Use of anonymous functions (closures)

Recently I’ve found myself with code that looks something like:

def foo(arg1, arg2, arg3...argN) do
   # Do some work, creating variables
   var1 = ...
   var2 = ...
   cond do
       Keyword.get(foo, :foobar) == abc &&  var1 == ... ->
         res =
          # Some more work using data in this conditional and variables before the cond
          cond1_do_something(res, ....)

       Keyword.get(foo, :barfoo) == cba &&  var2 == ... ->
          res = 
          # Some more work using data in this conditional and variables before the cond
          cond2_do_something(res, ....)
       ...
  end
end

The variables res1..N in the conditionals are computed using data computed before the cond as well as the data in each conditional, but the algorithm in each conditional is similar.

What I’ll do is create an anonymous function/closure to assist:

def foo(arg1, arg2, arg3...argN) do
   # Do some work, creating variables
  anon_fn_scope_1 = 
            fn args ->
                # Do work using variables here that are a closure
                # as well as the args passed to me
            end
   cond do
       Keyword.get(foo, :foobar) == abc &&  var1 == ... ->
         res = anon_fn_scope_1.(abc, var1 ...)
         cond1_do_something(res, ....)

       Keyword.get(foo, :barfoo) == cba &&  var2 == ... ->
         anon_fn_scope_2 = 
              fn -> 
                   v1 = ...
                   anon_fn_scope_1.(cba, var2, v1)
             end        
         cond2_do_something(anon_fn_scope_2, ....)

       ...
  end
end

Is that idiomatic Elixir? Using anonymous functions as closures to compute similar results later.

I think it’d be more common for me to make those defps and just pass in all the args in each case. However I think the thing you’re doing is just fine, and a nice use of functions!

1 Like

There’s nothing wrong with this code but I personally can never remember what values get captured in the closure (and when) so I’d just make private function(s) if I were you.

Or do both: have a defp with all the arguments, then capture specialized versions to be used later.

2 Likes

I might even write this based on an Enum.find_value/3 given a list of functions (or refs to defp named functions). It really depends on what dimension I think the code needs the most flexibility.