Nouveautés de F# 6
F# 6 apporte plusieurs améliorations au langage F# et à F# Interactive. Il est publié avec .NET 6.
Vous pouvez télécharger la dernière version du kit SDK .NET sur la page de téléchargements .NET.
Bien démarrer
F# 6 est disponible dans toutes les distributions de .NET Core et dans les outils de Visual Studio. Pour plus d’informations, consultez Prise en main de F#.
task {…}
F# 6 inclut la prise en charge native de la création de tâches .NET dans le code F#. Par exemple, examinons le code F# suivant pour la création d’une tâche compatible avec .NET :
let readFilesTask (path1, path2) =
async {
let! bytes1 = File.ReadAllBytesAsync(path1) |> Async.AwaitTask
let! bytes2 = File.ReadAllBytesAsync(path2) |> Async.AwaitTask
return Array.append bytes1 bytes2
} |> Async.StartAsTask
À l’aide de F# 6, ce code peut être réécrit comme suit.
let readFilesTask (path1, path2) =
task {
let! bytes1 = File.ReadAllBytesAsync(path1)
let! bytes2 = File.ReadAllBytesAsync(path2)
return Array.append bytes1 bytes2
}
La prise en charge des tâches était disponible avec F# 5 grâce aux excellentes bibliothèques TaskBuilder.fs et Ply. La migration du code vers la prise en charge intégrée ne présente en théorie aucune difficulté. Il existe néanmoins quelques différences : les espaces de noms et l’inférence de type diffèrent légèrement entre la prise en charge intégrée et ces bibliothèques, et des annotations de type supplémentaires peuvent être nécessaires. Si nécessaire, vous pouvez toujours utiliser ces bibliothèques communautaires avec F# 6 si vous les référencez explicitement et ouvrez les espaces de noms appropriés dans chaque fichier.
L’utilisation de task {…}
est très semblable à l’utilisation de async {…}
. L’utilisation de task {…}
présente plusieurs avantages par rapport à async {…}
:
- La surcharge de
task {...}
est plus réduite, ce qui permet éventuellement d’améliorer les performances des chemins de code critiques, où le travail asynchrone s’exécute rapidement. - Le débogage des exécutions pas à pas et des traces de pile est préférable pour
task {…}
. - Il est plus facile d’interagir avec des packages .NET qui attendent ou produisent des tâches.
Si vous maîtrisez async {…}
, il y a quelques différences à connaître :
task {…}
exécute immédiatement la tâche jusqu’au premier point d’attente.task {…}
ne propage pas implicitement un jeton d’annulation.task {…}
n’effectue pas de vérification d’annulation implicite.task {…}
ne prend pas en charge les « tailcalls » asynchrones. Cela signifie que l’utilisation récursive dereturn! ..
peut entraîner des dépassements de la capacité de la pile s’il n’y a pas d’attente asynchrone intermédiaire.
En règle générale, il est préférable d’utiliser task {…}
plutôt que async {…}
dans le nouveau code si vous interagissez avec des bibliothèques .NET qui utilisent des tâches, et si vous ne comptez pas sur des « tailcalls » de code asynchrones ou sur la propagation implicite de jetons d’annulation. Dans le code existant, vous ne devez passer à task {…}
qu’après avoir examiné votre code pour vous assurer que vous ne vous appuyez pas sur les caractéristiques de async {…}
mentionnées précédemment.
Cette fonctionnalité implémente F# RFC FS-1097.
Syntaxe d’indexation plus simple avec expr[idx]
F# 6 permet d’utiliser la syntaxe expr[idx]
pour indexer et découper les collections.
Jusqu’à F# 5 inclus, F# utilisait expr.[idx]
comme syntaxe d’indexation. L’autorisation de l’utilisation de expr[idx]
repose sur les commentaires répétés des personnes qui apprennent à utiliser le langage F# ou qui le découvrent pour la première fois, et selon lesquelles l’utilisation de l’indexation de la notation par points est perçue comme une divergence inutile par rapport aux pratiques courantes du secteur.
Il ne s’agit pas d’un changement cassant, car par défaut, aucun avertissement n’est émis lors de l’utilisation de expr.[idx]
. Toutefois, certains messages d’information suggérant des clarifications de code sont émis. Vous pouvez également activer d’autres messages d’information. Par exemple, vous pouvez activer un avertissement informatif facultatif (/warnon:3566
) pour commencer à signaler les utilisations de la notation expr.[idx]
. Pour plus d’informations, consultez Notation de l’indexeur.
Dans le nouveau code, nous recommandons l’utilisation systématique de expr[idx]
comme syntaxe d’indexation.
Cette fonctionnalité implémente F# RFC FS-1110.
Représentations de struct pour les modèles actifs partiels
F# 6 ajoute à la fonctionnalité des « motifs actifs » des représentations de struct facultatives pour les modèles actifs partiels. Cela vous permet d’utiliser un attribut pour contraindre un modèle actif partiel à renvoyer une option de valeur :
[<return: Struct>]
let (|Int|_|) str =
match System.Int32.TryParse(str) with
| true, int -> ValueSome(int)
| _ -> ValueNone
L’utilisation de l’attribut est obligatoire. Sur les sites d’utilisation, le code ne change pas. Le résultat net est que les allocations sont réduites.
Cette fonctionnalité implémente F# RFC FS-1039.
Opérations personnalisées surchargées dans les expressions de calcul
F# 6 vous permet d’utiliser CustomOperationAttribute sur les méthodes surchargées.
Examinons l’utilisation suivante d’un générateur d’expressions de calcul content
:
let mem = new System.IO.MemoryStream("Stream"B)
let content = ContentBuilder()
let ceResult =
content {
body "Name"
body (ArraySegment<_>("Email"B, 0, 5))
body "Password"B 2 4
body "BYTES"B
body mem
body "Description" "of" "content"
}
Ici, l’opération personnalisée body
accepte un nombre variable d’arguments de différents types. Ceci est pris en charge par l’implémentation du générateur suivant, qui utilise la surcharge :
type Content = ArraySegment<byte> list
type ContentBuilder() =
member _.Run(c: Content) =
let crlf = "\r\n"B
[|for part in List.rev c do
yield! part.Array[part.Offset..(part.Count+part.Offset-1)]
yield! crlf |]
member _.Yield(_) = []
[<CustomOperation("body")>]
member _.Body(c: Content, segment: ArraySegment<byte>) =
segment::c
[<CustomOperation("body")>]
member _.Body(c: Content, bytes: byte[]) =
ArraySegment<byte>(bytes, 0, bytes.Length)::c
[<CustomOperation("body")>]
member _.Body(c: Content, bytes: byte[], offset, count) =
ArraySegment<byte>(bytes, offset, count)::c
[<CustomOperation("body")>]
member _.Body(c: Content, content: System.IO.Stream) =
let mem = new System.IO.MemoryStream()
content.CopyTo(mem)
let bytes = mem.ToArray()
ArraySegment<byte>(bytes, 0, bytes.Length)::c
[<CustomOperation("body")>]
member _.Body(c: Content, [<ParamArray>] contents: string[]) =
List.rev [for c in contents -> let b = Text.Encoding.ASCII.GetBytes c in ArraySegment<_>(b,0,b.Length)] @ c
Cette fonctionnalité implémente F# RFC FS-1056.
Modèles « as »
Dans F# 6, le côté droit d’un modèle as
peut désormais être lui-même un modèle. Cela est important lorsqu’un test de type a donné un type plus fort à une entrée. Considérons par exemple le code suivant :
type Pair = Pair of int * int
let analyzeObject (input: obj) =
match input with
| :? (int * int) as (x, y) -> printfn $"A tuple: {x}, {y}"
| :? Pair as Pair (x, y) -> printfn $"A DU: {x}, {y}"
| _ -> printfn "Nope"
let input = box (1, 2)
Dans chaque cas de modèle, l’objet d’entrée est soumis à un test de type. Le côté droit du modèle as
peut maintenant être un autre modèle, qui peut lui-même correspondre à l’objet au type plus fort.
Cette fonctionnalité implémente F# RFC FS-1105.
Révisions de la syntaxe de mise en retrait
F# 6 supprime un certain nombre d’incohérences et de limitations dans son utilisation de la syntaxe de mise en retrait. Consultez RFC FS-1108. Cela résout 10 problèmes importants soulignés par les utilisateurs de F# depuis F# 4.0.
Par exemple, dans F# 5, le code suivant était autorisé :
let c = (
printfn "aaaa"
printfn "bbbb"
)
En revanche, le code suivant n’était pas autorisé (il générait un avertissement) :
let c = [
1
2
]
Dans F# 6, les deux sont autorisés. Cela facilite l’apprentissage de F# et simplifie son utilisation. Le contributeur de la communauté F# Hadrian Tang a ouvert la voie dans ce domaine, notamment en effectuant des tests systématiques remarquables et très utiles de cette fonctionnalité.
Cette fonctionnalité implémente F# RFC FS-1108.
Conversions implicites supplémentaires
Dans F# 6, nous avons activé la prise en charge d’autres conversions « implicites » et « dirigées par le type », comme décrit dans RFC FS-1093.
Cette modification offre trois avantages :
- Moins d’upcasts explicites sont nécessaires
- Moins de conversions explicites d’entiers sont nécessaires
- Ajout d’une prise en charge de première classe pour les conversions implicites de style .NET
Cette fonctionnalité implémente F# RFC FS-1093.
Conversions d’upcasts implicites supplémentaires
F# 6 implémente des conversions d’upcasts implicites supplémentaires. Par exemple, dans F# 5 et versions antérieures, les upcasts étaient nécessaires pour l’expression de retour lors de l’implémentation d’une fonction où les expressions disposaient de sous-types différents sur différentes branches, même lorsqu’une annotation de type était présente. Examinons le code F# 5 suivant :
open System
open System.IO
let findInputSource () : TextReader =
if DateTime.Now.DayOfWeek = DayOfWeek.Monday then
// On Monday a TextReader
Console.In
else
// On other days a StreamReader
File.OpenText("path.txt") :> TextReader
Ici, les branches de la conditionnelle calculent respectivement un TextReader
et un StreamReader
, et l’upcast a été ajouté pour que les deux branches disposent du type StreamReader. Dans F# 6, ces upcasts sont désormais ajoutés automatiquement. Le code est donc plus simple :
let findInputSource () : TextReader =
if DateTime.Now.DayOfWeek = DayOfWeek.Monday then
// On Monday a TextReader
Console.In
else
// On other days a StreamReader
File.OpenText("path.txt")
Vous pouvez éventuellement activer l’avertissement /warnon:3388
pour afficher un avertissement à chaque fois qu’un upcast implicite supplémentaire est utilisé, comme décrit dans Avertissements facultatifs pour les conversions implicites.
Conversions implicites d’entiers
Dans F# 6, les entiers de 32 bits sont élargis à des entiers de 64 bits lorsque les deux types sont connus. Par exemple, examinons une forme d’API classique :
type Tensor(…) =
static member Create(sizes: seq<int64>) = Tensor(…)
Dans F# 5, les littéraux d’entier d’int64 doivent être utilisés :
Tensor.Create([100L; 10L; 10L])
ou
Tensor.Create([int64 100; int64 10; int64 10])
Dans F# 6, l’élargissement se produit automatiquement pour int32
vers int64
, int32
vers nativeint
et int32
vers double
, lorsque les types de la source et de la destination sont connus pendant l’inférence de type. Ainsi, dans les cas tels que les exemples précédents, les littéraux int32
peuvent être utilisés :
Tensor.Create([100; 10; 10])
Malgré ce changement, dans la plupart des cas, F# continue d’utiliser l’élargissement explicite des types numériques. Par exemple, l’élargissement implicite ne s’applique pas aux autres types numériques, tels que int8
ou int16
, ou de float32
vers float64
, ou lorsque le type de la source ou de la destination est inconnu. Vous pouvez également activer l’avertissement /warnon:3389
pour afficher un avertissement à chaque fois qu’un élargissement numérique implicite est utilisé, comme décrit dans Avertissements facultatifs pour les conversions implicites.
Prise en charge de première classe pour les conversions implicites de style .NET
Dans F# 6, les conversions « op_Implicit » de .NET sont appliquées automatiquement dans le code F# lors de l’appel des méthodes. Par exemple, dans F# 5, il était nécessaire d’utiliser XName.op_Implicit
lors de l’utilisation des API .NET pour XML :
open System.Xml.Linq
let purchaseOrder = XElement.Load("PurchaseOrder.xml")
let partNos = purchaseOrder.Descendants(XName.op_Implicit "Item")
Dans F# 6, les conversions op_Implicit
sont appliquées automatiquement pour les expressions d’arguments lorsque les types sont disponibles pour l’expression source et le type cible :
open System.Xml.Linq
let purchaseOrder = XElement.Load("PurchaseOrder.xml")
let partNos = purchaseOrder.Descendants("Item")
Vous pouvez également activer l’avertissement /warnon:3395
pour afficher un avertissement à chaque fois qu’un élargissement des conversions op_Implicit
est utilisé dans les arguments de méthode, comme décrit dans Avertissements facultatifs pour les conversions implicites.
Notes
Dans la première version de F# 6, le numéro de cet avertissement était /warnon:3390
. Pour cause de conflit, ce numéro a ensuite été remplacé par le suivant : /warnon:3395
.
Avertissements facultatifs pour les conversions implicites
Les conversions implicites et dirigées par le type peuvent mal interagir avec l’inférence de type et conduire à un code plus difficile à comprendre. C’est pourquoi il existe des mesures d’atténuation pour éviter que cette fonctionnalité ne soit utilisée de manière abusive dans le code F#. Premièrement, le type de la source et de la destination doit être parfaitement connu, sans ambiguïté ni inférence de type supplémentaire. Deuxièmement, des avertissements d’adhésion peuvent être activés pour signaler toute utilisation de conversions implicites, avec un avertissement activé par défaut :
/warnon:3388
(upcast implicite supplémentaire)/warnon:3389
(élargissement numérique implicite)/warnon:3391
(op_Implicit aux arguments hors méthode, activé par défaut)/warnon:3395
(op_Implicit aux arguments de méthode)
Si votre équipe souhaite interdire l’utilisation des conversions implicites, vous pouvez également spécifier /warnaserror:3388
, /warnaserror:3389
, /warnaserror:3391
et /warnaserror:3395
.
Mise en forme des nombres binaires
F# 6 ajoute le modèle %B
aux spécificateurs de format disponibles pour les formats de nombres binaires. Examinons le code F# suivant :
printf "%o" 123
printf "%B" 123
Ce code imprime la sortie suivante :
173
1111011
Cette fonctionnalité implémente F# RFC FS-1100.
Abandons sur les liaisons d’utilisation
F# 6 permet d’utiliser _
dans une liaison use
, par exemple :
let doSomething () =
use _ = System.IO.File.OpenText("input.txt")
printfn "reading the file"
Cette fonctionnalité implémente F# RFC FS-1102.
InlineIfLambda
Le compilateur F# comprend un optimiseur qui procède à l’inlining du code. Dans F# 6, nous avons ajouté une nouvelle fonctionnalité déclarative qui permet au code d’indiquer de manière facultative que, si un argument est identifié comme une fonction lambda, cet argument doit toujours être « inlined » dans les sites d’appel.
Par exemple, examinons la fonction iterateTwice
suivante pour parcourir un tableau :
let inline iterateTwice ([<InlineIfLambda>] action) (array: 'T[]) =
for j = 0 to array.Length-1 do
action array[j]
for j = 0 to array.Length-1 do
action array[j]
Si le site d’appel est :
let arr = [| 1.. 100 |]
let mutable sum = 0
arr |> iterateTwice (fun x ->
sum <- sum + x)
Après l’inlining et d’autres optimisations, le code devient :
let arr = [| 1.. 100 |]
let mutable sum = 0
for j = 0 to arr.Length-1 do
sum <- sum + arr[j]
for j = 0 to arr.Length-1 do
sum <- sum + arr[j]
Contrairement aux versions précédentes de F#, cette optimisation est appliquée quelle que soit la taille de l’expression lambda concernée. Cette fonctionnalité peut également être utilisée pour implémenter un déroulement des boucles et des transformations similaires de manière plus fiable.
Un avertissement (/warnon:3517
, désactivé par défaut) peut être activé pour indiquer les emplacements de votre code où les arguments InlineIfLambda
ne sont pas liés aux expressions lambda sur les sites d’appel. En situation normale, cet avertissement ne doit pas être activé. Toutefois, dans certains types de programmation hautes performances, il peut être utile de s’assurer que tout le code est inlined et aplati.
Cette fonctionnalité implémente F# RFC FS-1098.
Code pouvant être repris
La prise en charge task {…}
de F# 6 repose sur une base appelée codeRFC FS-1087 pouvant être repris. Le code pouvant être repris est une caractéristique technique qui peut être utilisée pour créer de nombreux types de machines à états asynchrones et à hautes performances.
Fonctions de collection supplémentaires
FSharp.Core 6.0.0 ajoute cinq nouvelles opérations aux fonctions de collection de base. Ces fonctions sont les suivantes :
- List/Array/Seq.insertAt
- List/Array/Seq.removeAt
- List/Array/Seq.updateAt
- List/Array/Seq.insertManyAt
- List/Array/Seq.removeManyAt
Ces fonctions effectuent toutes des opérations de copie et de mise à jour sur le type de collection ou la séquence correspondante. Ce type d’opération est une forme de « mise à jour fonctionnelle ». Pour obtenir des exemples d’utilisation de ces fonctions, consultez la documentation correspondante, comme List.insertAt.
Par exemple, examinons le modèle, le message et la logique de mise à jour pour une application simple de type « Liste de tâches » écrite dans le style Elmish. Ici, l’utilisateur interagit avec l’application, ce qui génère des messages, et la fonction update
traite ces messages, ce qui produit un nouveau modèle :
type Model =
{ ToDo: string list }
type Message =
| InsertToDo of index: int * what: string
| RemoveToDo of index: int
| LoadedToDos of index: int * what: string list
let update (model: Model) (message: Message) =
match message with
| InsertToDo (index, what) ->
{ model with ToDo = model.ToDo |> List.insertAt index what }
| RemoveToDo index ->
{ model with ToDo = model.ToDo |> List.removeAt index }
| LoadedToDos (index, what) ->
{ model with ToDo = model.ToDo |> List.insertManyAt index what }
Avec ces nouvelles fonctions, la logique est claire et simple, et ne repose que sur des données immuables.
Cette fonctionnalité implémente F# RFC FS-1113.
La carte possède des clés et des valeurs
Dans FSharp.Core 6.0.0, le type Map
prend désormais en charge les propriétés Keys et Values. Ces propriétés ne copient pas la collection sous-jacente.
Cette fonctionnalité est documentée dans F# RFC FS-1113.
Intrinsèques supplémentaires pour NativePtr
FSharp.Core 6.0.0 ajoute de nouveaux intrinsèques au module NativePtr :
NativePtr.nullPtr
NativePtr.isNullPtr
NativePtr.initBlock
NativePtr.clear
NativePtr.copy
NativePtr.copyBlock
NativePtr.ofILSigPtr
NativePtr.toILSigPtr
Comme les autres fonctions de NativePtr
, ces fonctions sont inlined et leur utilisation émet des avertissements, sauf si /nowarn:9
est utilisé. L’utilisation de ces fonctions est limitée aux types non managés.
Cette fonctionnalité est documentée dans F# RFC FS-1109.
Types numériques supplémentaires avec annotations d’unités
Dans F# 6, les types ou alias d’abréviation de type suivants prennent désormais en charge les annotations d’unités de mesure. Les nouveaux ajouts sont affichés en gras :
Alias F# | Type CLR |
---|---|
float32 /single |
System.Single |
float /double |
System.Double |
decimal |
System.Decimal |
sbyte /int8 |
System.SByte |
int16 |
System.Int16 |
int /int32 |
System.Int32 |
int64 |
System.Int64 |
byte /uint8 |
System.Byte |
uint16 |
System.UInt16 |
uint /uint32 |
System.UInt32 |
uint64 |
System.UIn64 |
nativeint |
System.IntPtr |
unativeint |
System.UIntPtr |
Par exemple, vous pouvez annoter un entier non signé comme suit :
[<Measure>]
type days
let better_age = 3u<days>
Cette fonctionnalité est documentée dans F# RFC FS-1091.
Avertissements informatifs pour les opérateurs symboliques rarement utilisés
F# 6 fournit une aide qui dénormalise l’utilisation de :=
, !
, incr
et decr
dans F# 6 et versions ultérieures. L’utilisation de ces opérateurs et fonctions génère des messages d’information qui vous demandent de remplacer votre code par une utilisation explicite de la propriété Value
.
Dans la programmation en F#, les cellules de référence peuvent être utilisées pour les registres mutables alloués par tas. Bien qu’elles soient parfois utiles, elles sont rarement nécessaires dans le codage F# moderne, car let mutable
peut être utilisé à la place. La bibliothèque principale F# comprend deux opérateurs :=
et !
, et deux fonctions incr
et decr
spécifiquement liés aux appels de référence. La présence de ces opérateurs rend les cellules de référence plus centrales qu’elles ne devraient l’être dans la programmation en F#, ce qui oblige tous les programmeurs F# à connaître ces opérateurs. En outre, l’opérateur !
peut être facilement confondu avec l’opération not
en C# ou autre langage, ce qui constitue une source potentiellement subtile de bogues lors de la traduction du code.
Ce changement a pour but de réduire le nombre d’opérateurs que le programmeur F# doit connaître, et donc de simplifier F# pour les débutants.
Par exemple, examinons le code F# 5 suivant :
let r = ref 0
let doSomething() =
printfn "doing something"
r := !r + 1
Tout d’abord, les cellules de référence sont rarement nécessaires dans le codage F# moderne, car let mutable
peut normalement être utilisé à la place :
let mutable r = 0
let doSomething() =
printfn "doing something"
r <- r + 1
Si vous utilisez des cellules de référence, F# 6 émet un avertissement informatif vous demandant de remplacer la dernière ligne par r.Value <- r.Value + 1
et de consulter une aide supplémentaire sur l’utilisation appropriée des cellules de référence.
let r = ref 0
let doSomething() =
printfn "doing something"
r.Value <- r.Value + 1
Ces messages ne sont pas des avertissements ; il s’agit de « messages d’information » affichés dans l’IDE et dans la sortie du compilateur. F# reste rétrocompatible.
Cette fonctionnalité implémente F# RFC FS-1111.
Outil F# : .NET 6 par défaut pour l’écriture de scripts dans Visual Studio
Si vous ouvrez ou exécutez un script F# (.fsx
) dans Visual Studio, par défaut, le script sera analysé et exécuté en utilisant .NET 6 avec une exécution 64 bits. Cette fonctionnalité, qui était en préversion dans les versions ultérieures à Visual Studio 2019, est désormais activée par défaut.
Pour activer l’écriture de scripts .NET Framework, sélectionnez Outils>Options>Outils F#>F# Interactive. Définissez Utiliser l’écriture de scripts .NET Core sur faux, puis redémarrez la fenêtre F# Interactive. Ce paramètre affecte à la fois la modification et l’exécution des scripts. Pour activer l’exécution 32 bits pour l’écriture de scripts .NET Framework, définissez également F# Interactive 64 bits sur faux. Il n’existe aucune option 32 bits pour l’écriture de scripts .NET Core.
Outil F# : Épingler la version du kit de développement logiciel (SDK) de vos scripts F#
Si vous exécutez un script à l’aide de dotnet fsi
dans un répertoire contenant un fichier global.json avec un paramètre de kit SDK .NET, la version répertoriée du kit SDK .NET est utilisée pour exécuter et modifier le script. Cette fonctionnalité est disponible dans les versions ultérieures à F# 5.
Par exemple, supposons qu’un script se trouve dans un répertoire avec le fichier global.json suivant, qui spécifie une stratégie de version du kit SDK .NET :
{
"sdk": {
"version": "5.0.200",
"rollForward": "minor"
}
}
Si vous exécutez maintenant le script à l’aide de dotnet fsi
, à partir de ce répertoire, la version du kit SDK est respectée. Cette fonctionnalité vous permet de « verrouiller » le kit SDK utilisé pour compiler, analyser et exécuter vos scripts.
Si vous ouvrez et modifiez votre script dans Visual Studio ou d’autres IDE, l’outil respecte ce paramètre lors de l’analyse et de la vérification de votre script. Si le kit SDK est introuvable, vous devez l’installer sur votre ordinateur de développement.
Sous Linux et d’autres systèmes Unix, vous pouvez combiner cela avec un shebang afin de spécifier également une version du langage pour l’exécution directe du script. Simple shebang pour script.fsx
:
#!/usr/bin/env -S dotnet fsi
printfn "Hello, world"
À présent, le script peut être exécuté directement avec script.fsx
. Vous pouvez combiner ceci avec une version spécifique du langage autre que la version par défaut en procédant comme suit :
#!/usr/bin/env -S dotnet fsi --langversion:5.0
Notes
Ce paramètre est ignoré par les outils d’édition, qui analysent le script en supposant que la dernière version du langage est utilisée.
Suppression des fonctionnalités héritées
Depuis F# 2.0, certaines fonctionnalités héritées déconseillées génèrent des avertissements. L’utilisation de ces fonctionnalités dans F# 6 génère des erreurs, sauf si vous utilisez explicitement /langversion:5.0
. Les fonctionnalités qui génèrent des erreurs sont les suivantes :
- Paramètres génériques multiples utilisant un nom de type suffixé, par exemple
(int, int) Dictionary
. Cela génère une erreur dans F# 6. La syntaxeDictionary<int,int>
standard doit être utilisée à la place. #indent "off"
. Cela génère une erreur.x.(expr)
. Cela génère une erreur.module M = struct … end
. Cela génère une erreur.- Utilisation des entrées
*.ml
et*.mli
. Cela génère une erreur. - Utilisation de
(*IF-CAML*)
ou(*IF-OCAML*)
. Cela génère une erreur. - Utilisation de
land
,lor
,lxor
,lsl
,lsr
ouasr
en tant qu’opérateurs infixe. Il s’agit de mots clés infixes en F# car il en était de même en OCaml et ils ne sont pas définis dans FSharp.Core. L’utilisation de ces mots clés déclenche désormais un avertissement.
Cela implémente F# RFC FS-1114.