エンジニアのソフトウェア的愛情

または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか

RPN in Elixir

# Rpn.eval "3 1 - 2.1 +"
# => 4.1

defmodule Rpn do
  def eval(expression) do
    eval(tokenize(expression), [])
  end

  defp eval([], [result]), do: result
  defp eval(["+"|tokens], [rhs, lhs|stack]), do: eval(tokens, [lhs + rhs | stack])
  defp eval(["-"|tokens], [rhs, lhs|stack]), do: eval(tokens, [lhs - rhs | stack])
  defp eval(["*"|tokens], [rhs, lhs|stack]), do: eval(tokens, [lhs * rhs | stack])
  defp eval(["/"|tokens], [rhs, lhs|stack]), do: eval(tokens, [lhs / rhs | stack])
  defp eval([value|tokens], stack), do: eval(tokens, [value | stack])

  defp tokenize(expression) do
    tokens = Regex.scan( ~r/(?<op>[\+\-\*\/])|(?<float>\d+\.\d+)|(?<int>\d+)/, expression, capture: ["op", "int", "float"])
    Enum.map(
      tokens,
      fn
        ([op, "", ""]) -> op
        (["", int, ""]) -> String.to_integer(int)
        (["", "", float]) -> String.to_float(float)
      end
    )
  end
end


Regex.scan/3 がいささかトリッキー。使い方が合っているのか判断がつかない。