DEV Community

Discussion on: Daily Challenge #209 - Roman Numerals

Collapse
 
alexdesousa profile image
Alex de Sousa • Edited

Using pattern matching and tail recursion in Elixir:

defmodule Roman do
  @moduledoc false

  @spec to_integer(binary()) :: {:ok, pos_integer()} | :error
  def to_integer(number, acc \\ 0)

  def to_integer("", acc), do: {:ok, acc}

  def to_integer(number, acc) do
    with {value, rest} <- num(number) do
      to_integer(rest, acc + value)
    end
  end

  @spec num(binary()) :: {pos_integer(), binary()} | :error
  defp num(number)

  defp num("M" <> rest), do: {1000, rest}
  defp num("CM" <> rest), do: {900, rest}
  defp num("D" <> rest), do: {500, rest}
  defp num("CD" <> rest), do: {400, rest}
  defp num("C" <> rest), do: {100, rest}
  defp num("XC" <> rest), do: {90, rest}
  defp num("L" <> rest), do: {50, rest}
  defp num("XL" <> rest), do: {40, rest}
  defp num("X" <> rest), do: {10, rest}
  defp num("IX" <> rest), do: {9, rest}
  defp num("V" <> rest), do: {5, rest}
  defp num("IV" <> rest), do: {4, rest}
  defp num("I" <> rest), do: {1, rest}
  defp num(_), do: :error
end

solution = fn x ->
  case Roman.to_integer(x) do
    {:ok, value} -> value
    :error -> raise ArgumentError, message: "Wrong roman numeral format"
  end
end