2 votes

Est-il possible de rattraper cette erreur en utilisant le système de types, ou une conception différente ?

Je travaillais sur un petit remaniement qui consistait à convertir une partie d'un type de données à partir d'un fichier Int dans un wrapper de type nouveau. Avant :

data Account = Account {
  accountId :: Int
} deriving (Eq, Show)

Après :

newtype AccountId = AccountId Int deriving (Eq, Ord, Read, Show)

data Account = Account {
  accountId :: AccountId
} deriving (Eq, Show)

Dans une autre partie du programme, je fais passer accountId dans une fonction d'une bibliothèque tierce dans le but de filtrer les résultats qu'elle renvoie. Cependant, les filtres attendent Text et de convertir accountId pour cela, j'ai utilisé ce qui suit :

Text.pack $ show $ accountId someAccount

Il en résulte que des résultats erronés sont renvoyés au moment de l'exécution après le remaniement, en raison de la différence entre les paramètres suivants Show instances ( "123" vs "AccountId 123" ).

Existe-t-il un moyen, soit en utilisant le système de type, soit en utilisant une autre méthode pour convertir en Text qui permettrait de détecter ce problème au moment de la compilation ? Une solution qui me vient à l'esprit serait de définir une fonction d'aide qui prendrait le résultat de accountId someAccount et le convertit en Text mais peut-être existe-t-il une option/un modèle différent/meilleur dont je ne suis pas au courant.

4voto

Rein Henrichs Points 3592

Show est un outil de débogage à usage général et n'est pas destiné à être affiché. (Son cas d'utilisation prévu est spécifiquement de produire une lisible (dans le mot anglais read y Read ) version de la chaîne de caractères de vos données). Parce qu'il est d'usage général, show ne restreint pas suffisamment les types sur lesquels il opère pour être sûr pour l'utilisateur. votre cas d'utilisation. Vous pouvez, à la place, écrire des fonctions d'affichage qui sont spécifiques aux types que vous voulez afficher :

displayInt :: Int -> Text
displayInt = T.pack . show

displayAccountId :: AccountId -> Text
displayAccountId (AccountId x) = displayInt x

displayAccount :: Account -> Text
displayAccount = displayAccountId . accountId

Cela garantit qu'un compte ne peut être affiché que sous la forme de la représentation int de son id. Bien entendu, cette implémentation est fortement liée à l'implémentation de la fonction Account y AccountId . Pour réduire ce couplage, une classe de type peut être ajoutée :

class Display a where
    display :: a -> Text

instance Display Int where
    display = T.pack . show

instance Display AccountId where
    display (AccountId x) = display x

instance Display Account where
    display = display . accountId

Cela maintient la sécurité des types (vous ne pouvez pas accidentellement show plus la mauvaise chose) tout en résolvant - dans une certaine mesure - ce cas particulier du problème de l'expression.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X