Skip to content

Instantly share code, notes, and snippets.

@romul
Created May 3, 2016 10:44
Show Gist options
  • Save romul/29ca43111a4c4554a53db3075d2725e2 to your computer and use it in GitHub Desktop.
Save romul/29ca43111a4c4554a53db3075d2725e2 to your computer and use it in GitHub Desktop.
Reverse polish notation parser implemented in Elixir
defmodule RPN do
@binary_ops ~w(+ - / * ^)
@unary_ops ~w(+ - sqrt ln)
@ops @binary_ops ++ @unary_ops
def convert(str) do
str |> String.split(" ") |> Enum.reduce([], &convert_rpn(&1, &2)) |> hd
end
defp convert_rpn(op, [a, b | tail]) when op in @binary_ops do
case op do
"+" -> [b+a | tail]
"-" -> [b-a | tail]
"*" -> [b*a | tail]
"/" -> [b/a | tail]
"^" -> [:math.pow(b, a) | tail]
end
end
defp convert_rpn(op, [a | tail]) when op in @unary_ops do
case op do
"+" -> [a | tail]
"-" -> [-a | tail]
"sqrt" -> [:math.sqrt(a) | tail]
"ln" -> [:math.log(a) | tail]
end
end
defp convert_rpn(op, _) when op in @ops do
raise ArgumentError, message: "insufficient arguments count for #{op}"
end
defp convert_rpn(num_str, acc) do
number = case Float.parse(num_str) do
{num, _} -> num
:error -> raise ArgumentError, message: "#{num_str} is not a number"
end
[number | acc]
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment