Syntaxe

Les fondamentaux

Syntaxe - Clé

1er point fort de F♯ : langage succinct

Pour s'en rendre compte :

  1. Passons rapidement en revue sa syntaxe

  2. Ensuite vous pourrez commencer à jouer avec

    • ☝ C'est à l'usage que l'on mesure le côté succinct de F♯

💡 F♯ est généralement plus succinct que C♯ sauf ce qui concerne le fait d'être explicite.

Commentaires

(* This is block
   comment *)


// And this is line comment


/// XML doc summary


/// <summary>
/// Full XML doc
/// </summary>

Variables → Valeurs

  • Mot clé let pour déclarer/nommer une valeur

  • Pas besoin de ; en fin de déclaration

  • Liaison/Binding est immutable par défaut

    • const en JS, readonly pour un membre en C♯

  • Mutable avec let mutable et opérateur d'assignation <-

    • let en JS, var en C♯

    • Avec parcimonie, sur scope limité

Pièges ⚠️

Ne pas confondre la mutabilité d'une variable (la partie à gauche dans le binding) et la mutabilité d'un objet (la partie à droite du binding).

  • let empêche le binding d'être modifié c'est-à-dire affecter une nouvelle valeur à une variable.

  • let n'empêche pas un objet de muter...

  • ... à une exception près : les structures mutables (exemple : ArrayCollector) qui fonctionnent par valeur : quand on appelle une méthode qui modifie une structure (ex: Add ou Close), on obtient une nouvelle copie. C'est let mutable qui permet de garder une référence à cette nouvelle valeur.

Noms

  • Mêmes contraintes qu'en C♯

  • Sauf apostrophe ' (tick)

    • permise dans nom au milieu ou à la fin (mais pas au début)

    • en fin de nom → indique une variante (convention)

  • Entre doubles backticks

    • permettent n'importe quel caractère, en particulier les espaces, à l'exception des sauts de ligne)

Shadowing

  • Consiste à redéfinir une valeur avec un nom existant → La valeur précédente n'est plus accessible dans le scope courant

  • Interdit au niveau d'un module mais autorisé dans un sous-scope

  • Pratique mais peut être trompeur → Peu recommandé, sauf cas particulier

Annotation de type

  • Optionnelle grâce à l'inférence

  • Type déclaré après nom name: type (comme en TypeScript)

  • Valeur obligatoire, même si mutable 👍

Constante

  • What: Variable effacée à la compilation, remplacée par sa valeur

    • const C♯ - même idée en TS que const enum

  • How: Valeur décorée avec attribut Literal ⚠️ Attributs entre [< >] → Erreur fréquente au début : utiliser [ ] (comme en C♯)

  • Convention de nommage recommandée : PascalCase

Nombre

⚠️ Pas de conversion implicite entre nombre

→ 💡 Utiliser fonctions int, float, decimal

☝️ Cette règle a été assouplie dans certains cas avec F# 6.

String

Syntaxes complémentaires :

Chaîne avec interpolation en F# 8

Une chaîne interpolée ne peut pas contenir d'accolades ($"{xxx}") sauf à les doubler ($"{{xxx}}") . Depuis F# 8, c'est le caractère $ que l'on double ($$) pour indiquer le nombre d'accolades à partir duquel il y a interpolation.

Encodage

Les littéraux de chaînes (EN: string literals) sont encodés en Unicode.

On peut travailler en ASCII grâce au suffixe B mais on manipule alors un tableau de bytes :

Listes

Liste immuable → type spécial F♯ ≠ System.Collection.Generic.List<T>

  • Création avec [], éléments séparés par ; ou saut de ligne + indentation

    • ⚠️ Piège : ne pas utiliser , sinon on a en fait un seul élément, un tuple ! 📍Tuples

  • Notation ML du type int list = List<int>

    • ☝ Idiomatique que pour array, list et option 📍Type Option

Opérateurs sur les listes

  • :: Cons (pour "construction") → Ajoute un element en tête de liste

  • @ Append → Concatène 2 listes

  • .. Rangemin..max: plage de nombres ou de caractères entre le min et le max spécifiés (inclus)min..step..max: step définit l'écart entre 2 nombres successifs dans la plage

⚠️ Il faut mettre un espace avant [] pour créer une liste, pour différencier de l'accès par index.

Module List

Ce module contient les fonctions pour manipuler une ou plusieurs listes.

F♯ List
C♯ LINQ (IEnumerable)
JS Array

map, collect

Select(), SelectMany()

map(), flatMap()

exists, forall

Any(predicate), All()

some(), every()

filter

Where()

filter()

find, tryFind

×

find()

fold, reduce

Aggregate([seed]])

reduce()

average, sum

Average(), Sum()

×

Autres fonctions : cf. documentation

Fonctions

  • Fonction nommée : déclarée avec let

  • Convention de nommage : camelCase

  • Pas de return : la fonction renvoie toujours la dernière expression dans son corps

  • Pas de () autour de tous les paramètres

    • () autour d'un paramètre avec annotation de type (1) ou déconstruit tel qu'un tuple (2)

Fonctions de 0-n paramètres

  • Paramètres et arguments séparés par espace

    • ⚠️️ Piège : , sert à instancier 1 tuple = 1! paramètre

  • () : fonction sans paramètre, sans argument

  • Sans (), on déclare une valeur "vide", pas une fonction :

Fonction multi-ligne

Indentation nécessaire, mais pas de {}

Fonction anonyme

A.k.a. Lambda, arrow function

  • Déclarée avec fun et ->

  • En général entre () pour question de précédence

Note : taille de la flèche

  • Fine -> en F♯, Java

  • Large / fat => en C♯, JS

Convention de noms courts

  • x, y, z : paramètres de type valeurs simples

  • f, g, h : paramètres de type fonction

  • xs : liste de xx::xs (ou h::t) = head et tail d'une liste non vide

  • _ : discard / élément ignoré car non utilisé (comme en C♯ 7.0)

Bien adapté quand fonction courte ou très générique :

Piping

Opérateur pipe |> : même idée que | UNIX → Envoyer la valeur à gauche dans une fonction à droite → Ordre naturel "sujet verbe" - idem appel méthode d'un objet

Chainage de pipes - Pipeline

Comme fluent API en C♯ mais natif : pas besoin de méthode d'extension 👍

Façon naturelle de représenter le flux de données entre différentes opérations → Sans variable intermédiaire 👍

Écriture :

Expression if/then/else

💡 if b then x else y ≃ Opérateur ternaire C♯ b ? x : y

☝ Si then ne renvoie pas de valeur, else facultatif

Expression match

Équivalent en C♯ 8 :

Exception

Handling Exception

→ Bloc try/with -- ⚠️ Piège : try/catch

💡 Il n'y a pas de try/with/finally mais on peut faire imbriquer un try/finally dans un try/with.

Throwing Exception

→ Helpers failwith, invalidArg et nullArg

☝ Pour erreurs métier i.e. cas prévus, non exceptionnels : → Préférer le type Result a.k.a Railway-oriented programming 📍 Types monadiques

🔗 Handling Errors Elegantly https://devonburriss.me/how-to-fsharp-pt-8/

Attributs

Les attributs fonctionnent comme en C# pour décorer une classe, une méthode, etc.

La subtilité vient de la syntaxe :

  • C# [AttributUn][DeuxiemeAttribut] ou [AttributUn, DeuxiemeAttribut] → Attributs entre [...] et séparés par des ,

  • F# [<AttributUn>][<DeuxiemeAttribut>] ou [<AttributUn>; <DeuxiemeAttribut>] → Attributs entre [<...>] et séparés par des ;

Ordre des déclarations

⚠️ Déclarations ordonnées de haut en bas

  • Déclaration précède usage

  • Au sein d'un fichier

  • Entre fichiers dépendants

    • ☝ Importance de l'ordre des fichiers dans un .fsproj

  • Bénéfice : pas de dépendances cycliques 👍

Indentation

  • Très importante pour lisibilité du code

    • Crée struct. visuelle qui reflète struct. logique / hiérarchie

    • {} alignées verticalement (C♯) = aide visuelle mais < indentation

  • Essentielle en F♯ :

    • Façon de définir des blocs de code

    • Compilateur assure que indentation est correcte

👉 Conclusion :

  • F♯ force à bien indenter

  • Mais c'est pour notre bien

  • Car c'est bénéfique pour lisibilité du code 👍

Ligne verticale d'indentation

→ Démarre après let ... =, (, then/else, try/finally, do, -> (dans clause match) mais pas fun ! → Commence au 1er caractère non whitespace qui suit → Tout le reste du bloc doit s'aligner verticalement → L'indentation peut varier d'un bloc à l'autre

🔗 https://fsharpforfunandprofit.com/posts/fsharp-syntax/

Recommendations / Indentation

  • Utiliser des espaces, pas des tabulations

  • Utiliser 4 espaces par indentation

    • Facilite la détection visuelle des blocs

    • ... qui ne peut se baser sur les { } comme en C♯

  • Éviter un alignement sensible au nom, a.k.a vanity alignment

    • Risque de rupture de l'alignement après renommage → 💥 Compilation

    • Bloc trop décalé à droite → nuit à la lisibilité

☝️ Les règles concernant l'indentation ont été assouplies en F# 6.

Complément

🔗 Troubleshooting F# - Why won't my code compile?

Last updated

Was this helpful?