title: How to dynamically call an operator in Elixir
body: <p>I'm working my way through Dave's upcoming book on Elixir, and in one exercise I would like to dynamically construct a function reference to <code>Kernel.+/2</code>, <code>Kernel.-/2</code> etc, based on the contents of one character of a string, <code>'+'</code>, <code>'-'</code> and so on.</p>
  
  <p>Based on another SO question I expected to be able to call <code>apply/3</code> passing Kernel, :+ and the two numbers like this:</p>
  
  <pre><code>apply(Kernel, :+, [5, 7])
  </code></pre>
  
  <p>This doesn't work because (if I understand right) <code>Kernel.+/2</code> is a macro, not a function.  I looked up the source code, and <code>+</code> is defined in terms of <code>__op__</code>, and I can call it from <code>iex</code>:</p>
  
  <pre><code>__op__(:+, 5, 7)
  </code></pre>
  
  <p>This works until I put the :+ into a variable:</p>
  
  <pre><code>iex(17)&gt; h = list_to_atom('+')
  :+
  iex(18)&gt; __op__(h, 5, 7)
  ** (CompileError) iex:18: undefined function __op__/3
      src/elixir.erl:151: :elixir.quoted_to_erl/3
      src/elixir.erl:134: :elixir.eval_forms/4
  </code></pre>
  
  <p>And I'm guessing there's no way to call <code>__op__</code> using <code>apply/3</code>.</p>
  
  <p>Of course, the brute-force method gets the job done.</p>
  
  <pre><code>  defp _fn(?+), do: &amp;Kernel.+/2
    defp _fn(?-), do: &amp;Kernel.-/2
    defp _fn(?*), do: &amp;Kernel.*/2
  # defp _fn(?/), do: &amp;Kernel.//2   # Nope, guess again
    defp _fn(?/), do: &amp;div/2        # or &amp;(&amp;1 / &amp;2) or ("#{div &amp;1, &amp;2} remainder #{rem &amp;1, &amp;2}")
  </code></pre>
  
  <p>But is there something more concise and dynamic?</p>
  
  <hr>
  
  <p>José Valim nailed it with his answer below.  Here's the code in context:</p>
  
  <pre><code>  def calculate(str) do 
      {x, op, y} = _parse(str, {0, :op, 0})
      apply :erlang, list_to_atom(op), [x, y]
    end
  
    defp _parse([]     , acc      )                 , do: acc
    defp _parse([h | t], {a, b, c}) when h in ?0..?9, do: _parse(t, {a, b, c * 10 + h - ?0})
    defp _parse([h | t], {_, _, c}) when h in '+-*/', do: _parse(t, {c, [h], 0})
    defp _parse([_ | t], acc      )                 , do: _parse(t, acc)
  </code></pre>