Parcours
/
Elixir
Elixir
/
Exercices
/
Sous-débordement de pile
Sous-débordement de pile

Sous-débordement de pile

Exercice d'apprentissage

Introduction

Exceptions

Toutes les erreurs en Elixir implémentent le Exception Behaviour. Tout comme le Access Behaviour, le Exception Behaviour définit des fonctions de rappel qu'un module doit implémenter pour remplir le contrat logiciel du behaviour. Une fois une erreur définie, elle possède les propriétés suivantes :

  • Le nom du module définit le nom de l'erreur.
  • Le module définit une struct d'erreur.
  • Cette struct possède un champ :message.
  • Le module peut être utilisé avec raise/1 et raise/2 pour lever l'erreur voulue

Le Exception Behaviour définit aussi deux fonctions de rappel : message/1 et exception/1. Si elles ne sont pas implémentées, des implémentations par défaut seront utilisées. message/1 transforme la struct d'erreur en un message lisible lorsqu'elle est appelée avec raise. exception/1 permet d'ajouter du contexte supplémentaire au message lorsqu'elle est appelée avec raise/2

Définis une exception

Pour définir une exception à partir d'un module d'erreur, on utilise la macro defexception :

# Defines a minimal error, with the name `MyError`
defmodule MyError do
  defexception message: "error"
end

# Defines an error with a customized exception/1 function
defmodule MyCustomizedError do
  defexception message: "custom error"

  @impl true
  def exception(value) do
    case value do
      [] ->
        %MyCustomizedError{}

      _ ->
        %MyCustomizedError{message: "Alert: " <> value}
    end
  end
end

Utilise les exceptions

Une erreur définie peut s'utiliser comme une erreur native, avec raise/1 ou raise/2.

  • raise/1 lève une erreur précise par le nom de son module ou, si l'argument est une string, lève une RuntimeError avec cette string comme message.
  • raise/2 lève une erreur précise par le nom de son module et accepte un argument d'attributs qui sert à obtenir l'erreur avec le message approprié.

Instructions

Alors que tu poursuis ton travail chez Instruments of Texas, des progrès sont en cours sur l'implémentation en Elixir de la calculatrice RPN. Ton équipe aimerait pouvoir lever des erreurs plus spécifiques que les erreurs génériques fournies par la bibliothèque standard. Tu fais quelques recherches, mais tu as décidé de créer deux nouvelles erreurs qui implémentent le comportement Exception.

1. Erreur de division par zéro

Diviser un nombre par zéro produit un résultat indéfini, que l'équipe décide de représenter au mieux par une erreur.

Implémente le module DivisionByZeroError avec le message d'erreur : "division by zero occurred"

raise DivisionByZeroError
# => ** (DivisionByZeroError) division by zero occurred

2. Erreur en cas de stack underflow

Les calculatrices RPN utilisent une stack pour garder la trace des nombres avant de les additionner. L'équipe représente cette stack par une liste de nombres (entiers et à virgule flottante), par exemple : [3, 4.0]. Chaque opération prend un nombre précis de valeurs sur la pile pour effectuer son calcul. Quand il n'y a pas assez de nombres sur la pile, on parle d'une erreur de stack underflow. Implémente l'exception StackUnderflowError, qui fournit un message par défaut ainsi qu'un contexte supplémentaire facultatif

raise StackUnderflowError
# => ** (StackUnderflowError) stack underflow occurred

raise StackUnderflowError, "when dividing"
# => ** (StackUnderflowError) stack underflow occurred, context: when dividing

3. Écris une fonction de division

Implémente la fonction divide/1 qui prend une pile (une liste de deux nombres) et :

  • lève une erreur de stack underflow quand la pile ne contient pas assez de nombres
  • lève une erreur de division par zéro quand le diviseur vaut 0 (attention, la pile de nombres est stockée dans l'ordre inverse)
  • effectue la division quand aucune erreur n'est levée
RPNCalculator.Exception.divide([])
# => ** (StackUnderflowError) stack underflow occurred, context: when dividing

RPNCalculator.Exception.divide([0, 100])
# => ** (DivisionByZeroError) division by zero occurred

RPNCalculator.Exception.divide([4, 16])
# => 4

Attention, l'ordre de la liste est inversé !

Modifie via GitHub Le lien s'ouvre dans une nouvelle fenêtre ou un nouvel onglet
Elixir Exercism

Prêt à commencer Sous-débordement de pile ?

Inscris-toi sur Exercism pour apprendre et maîtriser Elixir avec 58 concepts168 exercices, et un vrai mentorat humain, le tout gratuitement.