Aller au contenu principal
Nicolas Cousin Tech SolutionsNicolas Cousin Tech Solutions
Module 7 sur 7

Synthèse

Où vous en êtes

Six modules plus tôt, vous n'aviez jamais ouvert dotnet fsi. Voici, en une phrase chacun, ce que vous savez désormais faire, et son ancrage côté C# :

  • let lie un nom à une valeur ou une fonction, avec un type déduit par le compilateur plutôt qu'écrit à la main comme en C# (module 2).
  • let vs mutable : une valeur F# est figée par défaut ; <- n'est autorisé que sur ce qui a été explicitement déclaré mutable — l'inverse de la variable C# par défaut (module 3).
  • |> et >> transforment un enchaînement d'appels imbriqués (le style Enumerable.Sum(Enumerable.Select(...))) en une lecture de gauche à droite, et permettent de construire une nouvelle fonction à partir de deux autres sans jamais leur fournir de valeur (module 4).
  • match remplace if/elif et switch pour brancher sur la forme d'une valeur, y compris pour décomposer un tuple en une seule étape (module 5).
  • Les records offrent une égalité structurelle par défaut — deux instances aux mêmes valeurs sont égales — là où une classe C# ordinaire compare des références (module 6).

Aucun de ces cinq points n'est un sujet isolé : l'exercice qui suit les combine tous dans un seul petit programme.

Exercice intégrateur

Vous gérez un petit catalogue de produits. Chaque produit a un nom et un prix. Objectif : classer chaque produit dans une tranche tarifaire, puis n'afficher que ceux qui ne sont pas « Économique ».

Ouvrez dotnet fsi et construisez le programme par étapes. Cet exercice recombine tout ce que vous avez vu jusqu'ici : prenez le temps qu'il vous faut, la durée indicative de ce module compte surtout la lecture, pas le rythme auquel vous devez enchaîner les cinq étapes.

Étape 1 — le record et les données, en réutilisant exactement la syntaxe du module 6 :

type Produit = { Nom: string; Prix: float };;

let catalogue =
    [ { Nom = "Stylo"; Prix = 1.5 }
      { Nom = "Clavier"; Prix = 45.0 }
      { Nom = "Écran"; Prix = 220.0 }
      { Nom = "Souris"; Prix = 15.0 } ];;

Notez qu'ici les éléments de la liste sont séparés par un simple retour à la ligne, sans ; — une alternative valide au point-virgule vu au module 4, tant que chaque élément reste aligné sur la même colonne. Les deux écritures produisent exactement la même liste.

Étape 2 — une fonction de classification, en réutilisant match avec des gardes comme au module 5 :

let trancheTarifaire (produit: Produit) =
    match produit.Prix with
    | p when p < 10.0 -> "Économique"
    | p when p < 100.0 -> "Standard"
    | _ -> "Premium";;

L'annotation (produit: Produit) n'est pas facultative ici comme elle l'était au module 2 : sans elle, le compilateur n'a aucun moyen de savoir, au moment d'accepter produit.Prix, à quel type appartient le paramètre produit — exactement le cas du module 2 où une annotation devient nécessaire dès qu'on accède à un membre d'un type précis.

Étape 3 — le pipeline, en réutilisant |>, List.filter et List.map comme au module 4 :

let resultat =
    catalogue
    |> List.filter (fun produit -> trancheTarifaire produit <> "Économique")
    |> List.map (fun produit -> produit.Nom, trancheTarifaire produit);;

Étape 4 — vérifier, en affichant le résultat :

printfn "%A" resultat;;

Sortie attendue :

[("Clavier", "Standard"); ("Écran", "Premium"); ("Souris", "Standard")]

« Stylo » n'apparaît pas : à 1,5, il est classé « Économique » par trancheTarifaire, donc exclu par le filtre de l'étape 3. Si votre résultat inclut encore « Stylo », relisez la condition du List.filter — c'est le même type d'erreur d'ordre ou de condition inversée qu'au module 4.

Étape 5 — écrire une fonction from scratch. Sans exemple à copier cette fois, écrivez vous-même une fonction estCher produit qui renvoie true si trancheTarifaire produit vaut "Premium", false sinon — en réutilisant match ou une simple comparaison, à votre choix. Testez-la sur les quatre produits du catalogue et vérifiez que seul « Écran » renvoie true.

Ce qui vous attend au palier Intermédiaire

Ce palier Débutant s'arrête volontairement avant plusieurs sujets qui prolongent directement ce que vous venez de pratiquer. Ils ne sont pas enseignés ici — seulement nommés, pour que vous sachiez où continuer :

  • Les unions discriminées (discriminated unions) : un moyen de décrire qu'une valeur peut prendre plusieurs formes distinctes et mutuellement exclusives — plus riche qu'un simple string de catégorie comme celui que trancheTarifaire renvoie ici.
  • Le type Option : une façon de représenter explicitement, dans le type lui-même, qu'une valeur peut être absente — sans recourir à null.
  • Result et la programmation orientée rail (railway-oriented programming) : une manière de faire circuler un échec possible à travers un pipeline |>, plutôt que de lever une exception.
  • La testabilité et le mocking en F# : comment structurer du code F# pour qu'il reste facile à tester unitairement, y compris quand il dépend de ressources externes.

Vous avez maintenant les bases nécessaires — let, l'immuabilité, |>/>>, match, les records — pour aborder ces quatre sujets quand le palier Intermédiaire sera disponible.

Vérifiez votre compréhension

Dans let trancheTarifaire (produit: Produit) = match produit.Prix with ..., pourquoi l'annotation (produit: Produit) est-elle nécessaire ici, alors qu'elle ne l'était pas pour la plupart des fonctions des modules précédents ?

Dans l'étape 3, catalogue |> List.filter (fun p -> trancheTarifaire p <> "Économique") |> List.map (fun p -> p.Nom, trancheTarifaire p), si vous intervertissez les deux étapes (map d'abord, puis un filter qui rappelle trancheTarifaire sur le résultat), que se passe-t-il ?

Pour écrire estCher produit qui renvoie true seulement si trancheTarifaire produit = "Premium", quelle formulation est la plus proche de l'esprit de match vu au module 5 ?

Envie d'être prévenu des prochains modules ?

L'Académie reste gratuite et en accès libre, sans inscription. Si vous voulez juste être averti par email à la sortie d'un nouveau module, c'est ici — aucune obligation, désinscription en un clic.