Rutas
/
Elixir
Elixir
/
Ejercicios
/
Calculadora RPN
Calculadora RPN

Calculadora RPN

Ejercicio de aprendizaje

Introducción

Errores

Los errores ocurren. En Elixir, aunque a menudo se dice que hay que «dejar que falle», hay ocasiones en las que necesitamos rescatar la llamada a la función hasta un estado conocido y válido para cumplir con un contrato de software. En algunos lenguajes, los errores se usan como método de flujo de control, pero en Elixir este patrón está desaconsejado. A menudo podemos reconocer las funciones que pueden lanzar un error solo por su nombre: las funciones que lanzan errores llevan un ! al final de su nombre. Esto contrasta con las funciones que devuelven {:ok, value} o :error. Mira estos ejemplos de la biblioteca:

Map.fetch(%{a: 1}, :b)
# => :error
Map.fetch!(%{a: 1}, :b)
# => raises KeyError

Try/Rescue

Elixir proporciona una construcción para rescatar de errores usando try .. rescue.

try do
  raise RuntimeError, "error"
rescue
  e in RuntimeError -> :error
end

Vamos a examinar esta construcción:

  • Línea 1, el bloque se declara con try.
  • Línea 2, aquí se coloca la llamada a la función que puede dar error; en este caso, estamos llamando a raise/2.
  • Línea 4, en la sección rescue, hacemos coincidencia de patrones con el nombre del módulo del error lanzado
    • a la izquierda de ->:
      • e se asigna a la struct del error.
      • in es una palabra clave.
      • RuntimeError es el error que queremos rescatar.
        • Si quisiéramos rescatar de todos los errores, podríamos usar _ en lugar del nombre del módulo u omitir la palabra clave in por completo.
    • a la derecha:
      • las instrucciones que se ejecutan si el error coincide.

Structs de error

Los errores (a los que a veces también se llama «excepciones») que rescatas de esta forma son structs. En Elixir, rescatar errores se hace muy rara vez. Normalmente, el error rescatado se registra o se envía a un servicio de monitorización externo, y luego se vuelve a lanzar. Esto significa que normalmente no nos importa la estructura interna del struct de error concreto.

En el concepto de excepciones aprenderás más sobre los structs de error, incluido cómo definir tu propio error personalizado.

Instrucciones

Mientras trabajas en Instruments of Texas, se te encarga trabajar en una calculadora experimental de notación polaca inversa [RPN] escrita en Elixir. Tu equipo tiene un problema: algunas operaciones lanzan errores y hacen que el proceso se caiga. Se te ha encargado escribir una función que envuelva la función de operación para que los errores se puedan gestionar de forma más elegante con código Elixir idiomático.

1. Avisa al equipo

Implementa la función calculate!/2 para llamar a la función de operación con la pila como único argumento. La función de operación está definida en otro lugar, pero sabes que puede completarse correctamente o lanzar un error.

stack = []
operation = fn _ -> :ok end
RPNCalculator.calculate!(stack, operation)
# => :ok

stack = []
operation = fn _ -> raise ArgumentError, "An error occurred" end
RPNCalculator.calculate!(stack, operation)
# => ** (ArgumentError) An error occurred

Los nombres de función que terminan en ! son un aviso para quien programa de que esa función puede lanzar un error

2. Envuelve el error

Cuando investigas un poco más, te das cuenta de que muchas funciones usan átomos y tuplas para indicar si tienen éxito o fallan. Implementa calculate/2 usando esta estrategia.

stack = []
operation = fn _ -> "operation completed" end
RPNCalculator.calculate(stack, operation)
# => {:ok, "operation completed"}

stack = []
operation = fn _ -> raise ArgumentError, "An error occurred" end
RPNCalculator.calculate(stack, operation)
# => :error

3. Transmite el mensaje

Algunos de los errores contienen información importante que tus compañeros de trabajo necesitan tener para garantizar el correcto funcionamiento del sistema. Implementa calculate_verbose/2 para transmitir el mensaje de error. El error es un struct que tiene un campo :message.

stack = []
operation = fn _ -> "operation completed" end
RPNCalculator.calculate_verbose(stack, operation)
# => {:ok, "operation completed"}

stack = []
operation = fn _ -> raise ArgumentError, "An error occurred" end
RPNCalculator.calculate_verbose(stack, operation)
# => {:error, "An error occurred"}
Editar en GitHub El enlace se abre en una ventana o pestaña nueva
Elixir Exercism

¿Listo para empezar Calculadora RPN?

Regístrate en Exercism para aprender y dominar Elixir con 58 conceptos168 ejercicios y mentoría humana real, todo gratis.