Syntaxe
Les fondamentaux
Syntaxe - Clé
1er point fort de F♯ : langage succinct
Pour s'en rendre compte :
Passons rapidement en revue sa syntaxe
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é
letpour déclarer/nommer une valeurPas besoin de
;en fin de déclarationLiaison/Binding est immutable par défaut
≃
consten JS,readonlypour un membre en C♯
Mutable avec
let mutableet opérateur d'assignation<-≃
leten JS,varen 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).
letempêche le binding d'être modifié c'est-à-dire affecter une nouvelle valeur à une variable.letn'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:
AddouClose), on obtient une nouvelle copie. C'estlet mutablequi 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
≃
constC♯ - même idée en TS queconst 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,listetoption📍Type Option
Opérateurs sur les listes
::Cons (pour "construction") → Ajoute un element en tête de liste@Append → Concatène 2 listes..Range →min..max: plage de nombres ou de caractères entre le min et le max spécifiés (inclus) →min..step..max:stepdé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
ListCe module contient les fonctions pour manipuler une ou plusieurs listes.
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
letConvention de nommage : camelCase
Pas de
return: la fonction renvoie toujours la dernière expression dans son corpsPas 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 argumentSans
(), 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
funet->En général entre
()pour question de précédence
☝ Note : taille de la flèche
Fine
->en F♯, JavaLarge / fat
=>en C♯, JS
Convention de noms courts
x,y,z: paramètres de type valeurs simplesf,g,h: paramètres de type fonctionxs: liste dex→x::xs(ouh::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/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
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
tabulationsUtiliser 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
Last updated
Was this helpful?