Track
/
Elixir
Elixir
/
Esercizi
/
Calcolatrice RPN
Calcolatrice RPN

Calcolatrice RPN

Esercizio di apprendimento

Introduzione

Errori

Gli errori capitano. In Elixir, anche se spesso si dice di «let it crash», ci sono momenti in cui dobbiamo recuperare la chiamata di funzione verso uno stato noto e valido per rispettare un contratto software. In alcuni linguaggi gli errori vengono usati come metodo di controllo del flusso, ma in Elixir questo schema è scoraggiato. Spesso riusciamo a riconoscere le funzioni che possono sollevare un errore già dal loro nome: le funzioni che sollevano errori hanno un ! alla fine del nome. Questo in contrasto con le funzioni che restituiscono {:ok, value} o :error. Guarda questi esempi dalla libreria:

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

Try/Rescue

Elixir fornisce un costrutto per recuperare dagli errori usando try .. rescue

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

Esaminiamo questo costrutto:

  • Riga 1, il blocco viene dichiarato con try.
  • Riga 2, qui va la chiamata di funzione che può generare un errore, in questo caso stiamo chiamando raise/2.
  • Riga 4, nella sezione rescue facciamo pattern matching sul nome del modulo dell'errore sollevato
    • alla sinistra di ->:
      • e corrisponde allo struct dell'errore.
      • in è una parola chiave.
      • RuntimeError è l'errore da recuperare.
        • Se volessimo recuperare da tutti gli errori, potremmo usare _ al posto del nome del modulo oppure omettere del tutto la parola chiave in.
    • alla destra:
      • le istruzioni da eseguire se l'errore corrisponde.

Struct di errore

Gli errori (a volte chiamati anche «eccezioni») che recuperi in questo modo sono struct. In Elixir, recuperare gli errori è molto raro. Di solito l'errore recuperato viene registrato nei log o inviato a un servizio di monitoraggio esterno, e poi risollevato. Questo significa che di solito non ci interessa la struttura interna dello struct di errore specifico.

Nel concetto di eccezioni imparerai di più sugli struct di errore, compresa la definizione di un errore personalizzato.

Istruzioni

Mentre lavori a Instruments of Texas, ti viene chiesto di occuparti di una calcolatrice sperimentale a notazione polacca inversa [RPN] scritta in Elixir. Il tuo team ha un problema: alcune operazioni generano errori e fanno crashare il processo. Ti è stato chiesto di scrivere una funzione che racchiuda la funzione di operazione, così che gli errori possano essere gestiti in modo più elegante con codice Elixir idiomatico.

1. Avvisa il team

Implementa la funzione calculate!/2 in modo che chiami la funzione di operazione con lo stack come unico argomento. La funzione di operazione è definita altrove, ma sai che può concludersi con successo oppure sollevare un errore.

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

I nomi di funzione che terminano con ! avvertono i programmatori che quella funzione potrebbe sollevare un errore

2. Racchiudi l'errore

Facendo altre ricerche, noti che molte funzioni usano atomi e tuple per indicare successo o fallimento. Implementa calculate/2 usando questa strategia.

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. Inoltra il messaggio

Alcuni errori contengono informazioni importanti che i tuoi colleghi devono conoscere per garantire il corretto funzionamento del sistema. Implementa calculate_verbose/2 per inoltrare il messaggio di errore. L'errore è una struct che ha 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"}
Modifica tramite GitHub Il link si apre in una nuova finestra o scheda
Elixir Exercism

Vuoi iniziare Calcolatrice RPN?

Iscriviti a Exercism per imparare e padroneggiare Elixir con 58 concetti168 esercizi e il mentoring di persone reali, tutto gratis.