F# est un langage de programmation fonctionnel, impératif et orienté objet pour la plate-forme .NET. F# est développé par Microsoft Research et son noyau est dérivé du langage OCaml, avec lequel il est fortement compatible. Ces deux langages de programmation font partie de la même famille que les langages ML. Depuis novembre 2010, Microsoft a mis à la disposition de tous les bibliothèques core et son compilateur F#, sous la licence Apache 22.
F# 9 est disponible et introduit une série d'améliorations pour rendre les programmes plus sûrs, plus résistants et plus performants. F# 9 est disponible dans .NET 9. Voici les principaux changements apportés par F# 9 :
- Types de référence annulables
- Propriétés d'union discriminées .Is*
- Les motifs actifs partiels peuvent renvoyer une option bool au lieu d'une option unit
- Mises à jour de la bibliothèque standard (FSharp.Core)
- Amélioration de la productivité des développeurs
- Amélioration des performances
Types de référence nullables
Bien que F# soit conçu pour éviter null, celles-ci peuvent se glisser dans les interfaces avec les bibliothèques .NET écrites en C#. F# fournit désormais un moyen sûr de traiter les types de référence qui peuvent avoir null comme valeur valide.
Voici quelques exemples :
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | // Declared type at let-binding let notAValue: string | null = null let isAValue: string | null = "hello world" let isNotAValue2: string = null // gives a nullability warning let getLength (x: string | null) = x.Length // gives a nullability warning since x is a nullable string // Parameter to a function let len (str: string | null) = match str with | null -> -1 | NonNull s -> s.Length // binds a non-null result // Parameter to a function let len (str: string | null) = let s = nullArgCheck "str" str // Returns a non-null string s.Length // binds a non-null result // Declared type at let-binding let maybeAValue: string | null = hopefullyGetAString() // Array type signature let f (arr: (string | null)[]) = () // Generic code, note 'T must be constrained to be a reference type let findOrNull (index: int) (list: 'T list) : 'T | null when 'T : not struct = match List.tryItem index list with | Some item -> item | None -> null |
Propriétés .Is* de l'union discriminée
Les unions discriminées ont désormais des propriétés auto-générées pour chaque cas, ce qui permet de vérifier si une valeur appartient à un cas particulier. Par exemple, pour le type suivant :
Code : | Sélectionner tout |
1 2 3 4 5 | type Contact = | Email of address: string | Phone of countryCode: int * number: string type Person = { name: string; contact: Contact } |
Code : | Sélectionner tout |
1 2 3 4 | let canSendEmailTo person = match person.contact with | Email _ -> true | _ -> false |
Code : | Sélectionner tout |
1 2 | let canSendEmailTo person =
person.contact.IsEmail |
Les motifs actifs partiels peuvent renvoyer bool au lieu de unit option
Auparavant, les motifs actifs partiels renvoyaient Some () pour indiquer une correspondance et None dans le cas contraire. Désormais, ils peuvent également renvoyer bool.
Par exemple, le motif actif pour ce qui suit :
Code : | Sélectionner tout |
1 2 3 | match key with | CaseInsensitive "foo" -> ... | CaseInsensitive "bar" -> ... |
Code : | Sélectionner tout |
1 2 3 4 5 | let (|CaseInsensitive|_|) (pattern: string) (value: string) = if String.Equals(value, pattern, StringComparison.OrdinalIgnoreCase) then Some () else None |
Code : | Sélectionner tout |
1 2 | let (|CaseInsensitive|_|) (pattern: string) (value: string) = String.Equals(value, pattern, StringComparison.OrdinalIgnoreCase) |
Mises à jour de la bibliothèque standard (FSharp.Core)
Fonctions aléatoires pour les collections
Les modules List, Array et Seq disposent de nouvelles fonctions d'échantillonnage et de mélange aléatoires. Cela facilite l'utilisation de F# pour la science des données, l'apprentissage automatique, le développement de jeux et d'autres scénarios où l'aléatoire est nécessaire.
Toutes les fonctions ont les variantes suivantes :
- Une qui utilise une instance Random implicite, partagée et à l'abri des threads
- Une fonction qui prend une instance Random comme argument
- Une qui prend une fonction de randomizer personnalisée, qui doit renvoyer une valeur flottante supérieure ou égale à 0,0 et inférieure à 1,0.
Quatre fonctions (chacune avec trois variantes) sont disponibles : Shuffle, Choice, Choices et Sample.
- Shuffle
Les fonctions Shuffle renvoient une nouvelle collection de même type et de même taille, chaque élément étant placé dans une position aléatoirement mélangée. La probabilité de se retrouver dans n'importe quelle position est pondérée uniformément en fonction de la longueur de la collection.Code : Sélectionner tout 1
2let allPlayers = [ "Alice"; "Bob"; "Charlie"; "Dave" ] let round1Order = allPlayers |> List.randomShuffle // [ "Charlie"; "Dave"; "Alice"; "Bob" ]
- Choice
Les fonctions Choice renvoient un seul élément aléatoire de la collection donnée. Le choix aléatoire est pondéré en fonction de la taille de la collection.Code : Sélectionner tout 1
2let allPlayers = [ "Alice"; "Bob"; "Charlie"; "Dave" ] let randomPlayer = allPlayers |> List.randomChoice // "Charlie"
- Choices
Les fonctions Choices sélectionnent N éléments de la collection d'entrée dans un ordre aléatoire, ce qui permet de sélectionner des éléments plus d'une fois.Code : Sélectionner tout 1
2let weather = [ "Raining"; "Sunny"; "Snowing"; "Windy" ] let forecastForNext3Days = weather |> List.randomChoices 3 // [ "Windy"; "Snowing"; "Windy" ]
- Sample
Les fonctions Sample sélectionnent N éléments de la collection d'entrée dans un ordre aléatoire, sans permettre aux éléments d'être sélectionnés plus d'une fois. N ne peut être supérieur à la longueur de la collection.Code : Sélectionner tout 1
2let foods = [ "Apple"; "Banana"; "Carrot"; "Donut"; "Egg" ] let today'sMenu = foods |> List.randomSample 3 // [ "Donut"; "Apple"; "Egg" ]
Amélioration de la productivité des développeurs
- Récupération de l'analyseur syntaxique
Des améliorations constantes ont été apportées à la récupération de l'analyseur syntaxique, ce qui signifie que les outils (par exemple, la coloration syntaxique) continuent de fonctionner avec le code lorsque vous êtes en train de l'éditer et qu'il peut ne pas être syntaxiquement correct à tout moment.
Par exemple, l'analyseur syntaxique récupère désormais les motifs as non terminés, les expressions d'objet, les déclarations de cas enum, les déclarations d'enregistrement, les motifs de constructeur primaire complexes, les identificateurs longs non résolus, les clauses de correspondance vides, les champs de cas d'union manquants et les types de champs de cas d'union manquants. - Diagnostics
Les diagnostics, ou la compréhension de ce que le compilateur n'aime pas dans votre code, sont une partie importante de l'expérience utilisateur avec F#. Il y a un certain nombre de messages de diagnostic nouveaux ou améliorés ou des emplacements de diagnostic plus précis dans F# 9.
En voici quelques-uns :- Méthode de remplacement ambiguë dans une expression d'objet
- Membres abstraits utilisés dans des classes non abstraites
- Propriété ayant le même nom qu'un cas d'union discriminée
- Inadéquation du nombre d'arguments d'un motif actif
- Unions avec champs dupliqués
- Utilisation de use ! avec and ! dans les expressions de calcul
Il existe également une nouvelle erreur à la compilation pour les classes comportant plus de 65 520 méthodes dans l'IL générée. Ces classes ne sont pas chargeables par le CLR et entraînent une erreur d'exécution. (Vous n'autoriserez pas autant de méthodes, mais il y a eu des cas avec du code généré). - Visibilité réelle
Il existe une bizarrerie dans la manière dont F# génère les assemblages qui fait que les membres privés sont écrits dans IL comme étant internes. Cela permet un accès inapproprié aux membres privés à partir de projets non F# qui ont accès à un projet F# via InternalsVisibleTo.
Il existe maintenant un correctif optionnel pour ce comportement disponible via l'option --realsig+ du compilateur. Essayez-le dans votre solution pour voir si l'un de vos projets dépend de ce comportement. Vous pouvez l'ajouter à vos fichiers .fsproj comme ceci :Code : Sélectionner tout 1
2
3<PropertyGroup> <RealSig>true</RealSig> </PropertyGroup>
Amélioration des performances
Optimisation des vérifications d'égalité
Les vérifications d'égalité sont désormais plus rapides et allouent moins de mémoire.
Par exemple :
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 | [<Struct>] type MyId = val Id: int new id = { Id = id } let ids = Array.init 1000 MyId let missingId = MyId -1 // used to box 1000 times, doesn't box anymore let _ = ids |> Array.contains missingId |
Résultats de l'évaluation comparative des fonctions de tableau affectées, appliquées à une structure à 2 membres
Avant :
Après :
Source : Présentation de F# 9
Et vous ?
Pensez-vous que ces améliorations sont crédibles ou pertinentes ?
Quel est votre avis sur le sujet ?
Voir aussi :
La version 6 de F#, le langage de programmation fonctionnel conçu par Microsoft, est disponible, plus rapide et plus interopérable, elle apporte de nouvelles fonctions
Annonces et mises à jour de .NET à la Microsoft Build 2024 : intégration profonde de l'IA, simplification du développement-natif avec .Net Aspire, ainsi que des améliorations des fonctionnalités C# pour C# 13
Microsoft partage sa vision initiale de .NET 9 et publie le premier aperçu de la nouvelle version du framework, dont les domaines d'intérêt sont le développement d'apps cloud-natives et intelligentes