Parcours
/
Elm
Elm
/
Programme
/
Types opaques
Ty

Types opaques en Elm

2 exercices

À propos de Types opaques

Introduction

Les types opaques sont une technique d'encapsulation en Elm. Certains parlent aussi de masquage des informations, ou de masquage des détails d'implémentation. Ils servent aussi couramment à imposer une validation, en suivant le motif Parse, don't validate. Par exemple, tu peux avoir un type opaque EmailAddress, qui ne peut contenir que des adresses e-mail valides (contrairement à une String, qui peut contenir n'importe quoi).

Crée un type opaque

Les types personnalisés ont une ou plusieurs variantes, et le compilateur génère automatiquement une fonction pour créer chaque variante, en utilisant le nom de la variante. Ce sont les seuls moyens de créer un type personnalisé. Le compilateur autorise aussi la déstructuration de ces variantes.

type Maybe a
    = Nothing --> Variant implies a 'Nothing' function, with type 'Maybe a', and destructuring of 'Nothing'
    | Just a  --> Variant implies a 'Just' function, with type 'a -> Maybe a', and destructuring of 'Just _'

Par défaut, tout cela est interne au fichier / au module, et on utilise le mot-clé exposing pour choisir ce que l'on exporte. Le module Maybe expose le type Maybe (pour que d'autres modules puissent utiliser des valeurs Maybe existantes), et expose aussi les variantes Nothing et Just (pour que d'autres modules puissent créer et déstructurer des valeurs Maybe). Il utilise la syntaxe suivante pour cela. La partie Maybe(..) indique à Elm d'exposer toutes les variantes, ainsi que la définition du type personnalisé.

module Maybe exposing
  ( Maybe(..)
  -- ...
  )

Pour créer un type opaque, il suffit de choisir de ne pas exporter les variantes. Pour faire cela avec le type Maybe, tu utiliserais la syntaxe suivante :

module Maybe exposing
  ( Maybe
  -- ...
  )

Quand tu fais cela, tu as presque toujours besoin de fournir un autre moyen de créer et d'obtenir les variantes, en exposant des fonctions personnalisées. Ces fonctions personnalisées te permettent d'appliquer une certaine logique au moment de créer et d'obtenir les variantes. Cela masque les détails d'implémentation internes du module, et signifie que tu peux modifier les détails d'implémentation autant que tu veux, tant que les fonctions exposées restent les mêmes. Cela te permet aussi de préserver les invariants lors de la création et de l'utilisation du type.

Parse, don't validate

L'utilisation la plus courante des types opaques est sans doute d'imposer une validation, en suivant le motif Parse, don't validate. Dans ce motif, on expose une fonction qui prend une entrée avec moins de structure ou de sûreté de typage que ce que l'on souhaite, comme une String, puis on l'analyse pour en faire un type plus structuré, comme EmailAddress, en renvoyant soit le type, soit une erreur (généralement Maybe ou Result).

Par exemple, dans le code ci-dessous, il n'est possible pour des modules externes de créer un type EmailAddress qu'en utilisant la fonction parseEmailAddress, donc quand tu travailles avec le type EmailAddress, tu es certain qu'il est valide.

module EmailAddress exposing ( EmailAddress, parseEmailAddress, getEmailAddress )

-- The `EmailAddress` custom type has one variant, also called `EmailAddress`
-- When a custom type has one variant, it is idiomatic to use the same name for both.
type EmailAddress = 
  EmailAddress String

-- create an EmailAddress variant
parseEmailAddress: String -> Maybe EmailAddress
parseEmailAddress candidateEmailAddress =   
  if isValidEmailAddress candidateEmailAddress then
    Just (EmailAddress candidateEmailAddress)
  else
    Nothing

-- get an EmailAddress variant
getEmailAddress: EmailAddress -> String
getEmailAddress ( EmailAddress  emailAdress ) =
  emailAdress

isValidEmailAddress: String -> bool
-- ... 
Modifie via GitHub Le lien s'ouvre dans une nouvelle fenêtre ou un nouvel onglet

Apprends Types opaques

L'entraînement est verrouillé

Déverrouille 1 exercice de plus pour t'entraîner sur Types opaques