Trilhas
/
Elixir
Elixir
/
Exercícios
/
Calculadora RPN
Calculadora RPN

Calculadora RPN

Exercício de aprendizagem

Introdução

Erros

Erros acontecem. No Elixir, embora muitas pessoas costumem dizer "let it crash", há momentos em que precisamos resgatar a chamada da função para um estado bom conhecido, a fim de cumprir um contrato de software. Em algumas linguagens, os erros são usados como forma de controle de fluxo, mas no Elixir esse padrão é desencorajado. Muitas vezes conseguimos reconhecer funções que podem lançar um erro só pelo nome: funções que lançam erros têm ! no final do nome. Isso em comparação com funções que retornam {:ok, value} ou :error. Veja estes exemplos da biblioteca:

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

Try/Rescue

O Elixir oferece uma construção para resgatar erros usando try .. rescue

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

Vamos examinar essa construção:

  • Linha 1, o bloco é declarado com try.
  • Linha 2, a chamada de função que pode dar erro fica aqui; neste caso, estamos chamando raise/2.
  • Linha 4, na seção rescue, fazemos pattern matching no nome do Módulo do erro lançado
    • no lado esquerdo de ->:
      • e corresponde à struct de erro.
      • in é uma palavra-chave.
      • RuntimeError é o erro que queremos resgatar.
        • Se quiséssemos resgatar de todos os erros, poderíamos usar _ no lugar do nome do módulo ou omitir completamente a palavra-chave in.
    • no lado direito:
      • as instruções a serem executadas se o erro corresponder.

Structs de erro

Os erros (às vezes também chamados de "exceções") que você resgata dessa forma são structs. Resgatar erros no Elixir é algo muito raro. Normalmente, o erro resgatado é registrado em log ou enviado a um serviço externo de monitoramento e, em seguida, lançado novamente. Isso significa que geralmente não nos importamos com a estrutura interna da struct de erro específica.

No conceito de Exceptions, você vai aprender mais sobre structs de erro, incluindo como definir seu próprio erro personalizado.

Instruções

Enquanto trabalha na Instruments of Texas, você é encarregado de trabalhar em uma calculadora experimental de Notação Polonesa Reversa [RPN] escrita em Elixir. Sua equipe está com um problema: algumas operações geram erros e travam o processo. Você foi encarregado de escrever uma função que encapsula a função de operação para que os erros possam ser tratados de forma mais elegante com código Elixir idiomático.

1. Avise a equipe

Implemente a função calculate!/2 para chamar a função de operação com a pilha como único argumento. A função de operação está definida em outro lugar, mas você sabe que ela pode ser concluída com sucesso ou gerar um erro.

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

Nomes de funções que terminam em ! são um aviso aos programadores de que essa função pode gerar um erro

2. Envolva o erro

Ao pesquisar mais, você percebe que muitas funções usam átomos e tuplas para indicar sucesso ou falha. Implemente calculate/2 usando essa estratégia.

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. Repasse a mensagem

Alguns dos erros contêm informações importantes que seus colegas de trabalho precisam ter para garantir o funcionamento correto do sistema. Implemente calculate_verbose/2 para repassar a mensagem de erro. O erro é uma struct que tem um 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 via GitHub O link abre em uma nova janela ou aba
Elixir Exercism

Tudo pronto para começar Calculadora RPN?

Crie sua conta no Exercism para aprender e dominar Elixir com 58 conceitos168 exercícios e mentoria humana de verdade, tudo de graça.