Patterns

Généralités

Patterns = règles pour détecter la structure de données en entrée

Utilisés abondamment en F♯

  • Dans match expression, let binding de valeurs et de paramètres de fonctions

  • Très pratiques pour manipuler les types algébriques F♯ (tuple, record, union)

  • Composables : supporte plusieurs niveaux d'imbrication

  • Assemblables par ET/OU logiques

  • Supporte les littéraux : 1.0, "test"...

Wildcard Pattern

Représenté par _, seul ou combiné avec un autre pattern

Toujours vrai → A placer en dernier dans une match expression

⚠️ Toujours chercher en 1er à traiter exhaustivement/explicitement tous les cas Quand impossible, utiliser alors le _

match option with
| Some 1 -> ...
| _ -> ...              // ⚠️ Non exhaustif

match option with
| Some 1 -> ...
| Some _ | None -> ...  // 👌 \+ exhaustif

Constant Pattern

Détecte constantes, null et littéraux de nombre, char, string, enum

Notes :

  • Le pattern de Three est aussi classé en tant que Identifier Pattern 📍

  • Pour le matching de null, on parle aussi de Null Pattern

Identifier Pattern

Détecte les cases d'un type union ainsi que leur éventuel contenu

Variable Pattern

Assigne la valeur détectée à une "variable" pour l'utiliser ensuite

Exemple : variables firstName et lastName ci-dessous

⚠️ On ne peut pas lier à plusieurs reprises vers la même variable

Solutions : utiliser 2 variables puis vérifier l'égalité

Champs nommés de cases d'union

Plusieurs possibilités :

  1. Pattern "anonyme" du tuple complet → Il faut déconstruire tous les champs du tuple. → On utilise la virgule , pour séparer ces champs.

  2. Pattern d'un seul champ par son nom → Field = value

  3. Pattern de plusieurs champs par leur nom → F1 = v1; F2 = v2 ⚠️ Ne pas confondre avec l'option 1 : → Le délimiteur est ici le point-virgule ; et non la virgule , !

Alias Pattern

as permet de nommer un élément dont le contenu est déconstruit

💡 Marche aussi dans les fonctions :

OR et AND Patterns

Permettent de combiner deux patterns (nommés P1 et P2 ci-après)

  • P1 | P2 → P1 ou P2. Ex : Rectangle (0, _) | Rectangle (_, 0)

  • P1 & P2 → P1 et P2. Utilisé surtout avec 🚀 Active Patterns📍

💡 On peut utiliser la même variable (name ci-dessous) dans 2 patterns :

Parenthesized Pattern

Usage des parenthèses () pour grouper des patterns, pour gérer la précédence

Note : la ligne ① ne compilerait sans faire () :: tail

⚠️ Les parenthèses compliquent la lecture

💡 Essayer de s'en passer quand c'est possible

Construction Patterns

Reprennent syntaxe de construction d'un type pour le déconstruire

  • Cons et List Patterns

  • Array Pattern

  • Tuple Pattern

  • Record Pattern

Cons et List Patterns

≃ Inverses de 2 types de construction d'une liste, avec même syntaxe

Cons Pattern : head :: tail → décompose une liste (avec >= 1 élément) en :

  • Head : 1er élément

  • Tail : autre liste avec le reste des éléments - peut être vide

List Pattern : [items] → décompose une liste en 0..N éléments

  • [] : liste vide

  • [x] : liste avec 1 élément mis dans la variable x

  • [x; y] : liste avec 2 éléments mis dans les variables x et y

  • [_; _] : liste avec 2 éléments ignorés

💡 x :: [][x], x :: y :: [][x; y]...

La match expression par défaut combine les 2 patterns : → Une liste est soit vide [], soit composée d'un item et du reste : head :: tail

Les fonctions récursives parcourant une liste utilise le pattern [] pour stopper la récursion :

Array Pattern

Syntaxe: [| items |] pour 0..N items entre ;

☝ Il n'existe pas de pattern pour les séquences, vu qu'elles sont "lazy".

Tuple Pattern

Syntaxe : items ou (items) pour 2..N items entre ,

💡 Pratique pour pattern matcher plusieurs valeurs en même temps

Record Pattern

Syntaxe : { Fields } pour 1..N Field = variable entre ;

  • Pas obligé de spécifier tous les champs du Record

  • En cas d'ambiguïté, qualifier le champ : Record.Field

💡 Marche aussi pour les paramètres d'une fonction :

⚠️ Rappel : il n'y a pas de pattern pour les Records anonymes !

Type Test Pattern

Syntaxe : my-object :? sub-type

Renvoie un boolis C♯ (my-object is sub-type)

Usage : avec une hiérarchie de types

☝️ Remarque : l'opérateur :? n'est pas conçu pour vérifier des évidences car il adopte alors un comportement déroutant : (Exemple tiré de cette question stackoverflow)

Bloc try/with

On rencontre fréquemment ce pattern dans les blocs try/with :

Boxing

Le Type Test Pattern ne marche qu'avec des types références.

→ Pour un type valeur ou inconnu, il faut le convertir en objet (a.k.a boxing)

Last updated

Was this helpful?