Novinky v F# 6

F# 6 přidává několik vylepšení jazyka F# a F# Interactive. Vydává se s .NET 6.

Nejnovější sadu .NET SDK si můžete stáhnout ze stránky pro stahování .NET.

Začínáme

F# 6 je k dispozici ve všech distribucích .NET Core a nástrojích sady Visual Studio. Další informace najdete v tématu Začínáme s jazykem F#.

úkol {...}

F# 6 obsahuje nativní podporu pro vytváření úloh .NET v kódu jazyka F#. Představte si například následující kód jazyka F#, který vytvoří . Úloha kompatibilní s rozhraním 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

Pomocí F# 6 je možné tento kód přepsat následujícím způsobem.

let readFilesTask (path1, path2) =
   task {
        let! bytes1 = File.ReadAllBytesAsync(path1)
        let! bytes2 = File.ReadAllBytesAsync(path2)
        return Array.append bytes1 bytes2
   }

Podpora úloh byla k dispozici pro F# 5 prostřednictvím vynikajících knihoven TaskBuilder.fs a Ply. Migrace kódu na integrovanou podporu by měla být jednoduchá. Existují však některé rozdíly: obory názvů a odvození typů se mírně liší mezi integrovanou podporou a těmito knihovnami a můžou být potřeba některé další poznámky k typům. V případě potřeby můžete tyto knihovny komunity používat s jazykem F# 6, pokud na ně explicitně odkazujete a otevřete v každém souboru správné obory názvů.

Použití task {…} je velmi podobné použití async {…}. Použití task {…} má několik výhod oproti async {…}:

  • Režie je nižší, což může zlepšit výkon v horkých task {...} cestách kódu, kde se asynchronní práce provádí rychle.
  • Lepší je ladění krokování a trasování zásobníku task {…} .
  • Spolupráce s balíčky .NET, které očekávají nebo vytvářejí úlohy, je jednodušší.

Pokud jste obeznámeni async {…}, je potřeba si uvědomit některé rozdíly:

  • task {…} okamžitě spustí úlohu na první bod await.
  • task {…} nešíruje implicitně token zrušení.
  • task {…} neprovádí implicitní kontroly zrušení.
  • task {…} nepodporuje asynchronní tailcalls. To znamená, že použití return! .. rekurzivně může vést k přetečení zásobníku, pokud nedojde k žádným asynchronním čekáním.

Obecně byste měli zvážit použití task {…}async {…} v novém kódu, pokud spolupracujete s knihovnami .NET, které používají úlohy, a pokud nespoléháte na asynchronní tailcalls nebo implicitní šíření tokenu zrušení. V existujícím kódu byste měli přepnout task {…} pouze po kontrole kódu, abyste se ujistili, že se nespoléháte na výše uvedené vlastnosti async {…}.

Tato funkce implementuje F# RFC FS-1097.

Jednodušší syntaxe indexování s využitím expr[idx]

F# 6 umožňuje syntaxi expr[idx] pro indexování a řezy kolekcí.

Jazyk F# 5 a včetně jazyka F# 5 se používá expr.[idx] jako syntaxe indexování. Povolení použití expr[idx] je založeno na opakované zpětné vazbě z učení jazyka F# nebo na prvním zobrazení jazyka F# jako zbytečného rozdílu od standardní praxe v oboru.

Nejedná se o zásadní změnu, protože ve výchozím nastavení nejsou generována žádná upozornění při použití expr.[idx]. Některé informační zprávy, které navrhují objasnění kódu, se však vygenerují. Volitelně můžete aktivovat i další informační zprávy. Můžete například aktivovat volitelné informační upozornění (/warnon:3566) pro zahájení vytváření sestav použití expr.[idx] notace. Další informace naleznete v tématu Zápis indexeru.

V novém kódu doporučujeme jako syntaxi indexování systematicky používat expr[idx] .

Tato funkce implementuje F# RFC FS-1110.

Reprezentace struktur pro částečné aktivní vzory

F# 6 rozšiřuje funkci aktivních vzorů o volitelné reprezentace struktur pro částečné aktivní vzory. To vám umožní použít atribut k omezení částečného aktivního vzoru k vrácení možnosti hodnoty:

[<return: Struct>]
let (|Int|_|) str =
   match System.Int32.TryParse(str) with
   | true, int -> ValueSome(int)
   | _ -> ValueNone

Je vyžadováno použití atributu. V webech využití se kód nezmění. Čistým výsledkem je snížení přidělení.

Tato funkce implementuje F# RFC FS-1039.

Přetížené vlastní operace ve výpočetních výrazech

F# 6 umožňuje používat CustomOperationAttribute u přetížených metod.

Zvažte následující použití tvůrce contentvýpočetních výrazů:

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"
    }

body Tady vlastní operace přebírá různý počet argumentů různých typů. To je podporováno implementací následujícího tvůrce, který používá přetížení:

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

Tato funkce implementuje F# RFC FS-1056.

Vzory "as"

V jazyce F# 6 může být pravá strana as vzoru sama o sobě vzorem. To je důležité v případě, že test typu zadal silnější typ vstupu. Představte si například následující kód:

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)

V každém případě se vstupní objekt testuje typem. Pravá strana as vzoru teď může být dalším vzorem, který se může shodovat s objektem silnějšího typu.

Tato funkce implementuje F# RFC FS-1105.

Revize syntaxe odsazení

F# 6 odebere řadu nekonzistence a omezení při použití syntaxe podporující odsazení. Viz RFC FS-1108. Tím se vyřeší 10 významných problémů zvýrazněných uživateli jazyka F# od verze F# 4.0.

Například v F# 5 byl povolen následující kód:

let c = (
    printfn "aaaa"
    printfn "bbbb"
)

Následující kód však nebyl povolen (vytvořil upozornění):

let c = [
    1
    2
]

V F# 6 jsou oba povolené. To usnadňuje a usnadňuje učení jazyka F#. Přispěvatel komunity F# Hadrian Tang vedl cestu k tomuto, včetně pozoruhodných a vysoce cenných systematických testů této funkce.

Tato funkce implementuje F# RFC FS-1108.

Další implicitní převody

V F# 6 jsme aktivovali podporu dalších "implicitních" a "typově orientovaných" převodů, jak je popsáno v DOKUMENTU RFC FS-1093.

Tato změna přináší tři výhody:

  1. Vyžaduje se méně explicitních upcastů.
  2. Vyžaduje se méně explicitních celočísných převodů.
  3. Prvotřídní podpora pro . Přidá se implicitní převody ve stylu NET.

Tato funkce implementuje F# RFC FS-1093.

Další implicitní převody upcastu

F# 6 implementuje další implicitní převody upcastu. Například v jazyce F# 5 a starších verzích byly pro návratový výraz potřeba upcasty při implementaci funkce, ve které měly výrazy různé podtypy na různých větvích, i když byla k dispozici poznámka typu. Vezměte v úvahu následující kód F# 5:

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

Tady větve podmíněného výpočetního objektu a TextReaderStreamReader v uvedeném pořadí a upcast byl přidán, aby obě větve měly typ StreamReader. V jazyce F# 6 se teď tato přesměrová vysílání přidávají automaticky. To znamená, že kód je jednodušší:

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")

Volitelně můžete povolit, aby se upozornění /warnon:3388 zobrazovala v každém okamžiku, kdy se použije další implicitní upcast, jak je popsáno v volitelných upozorněních pro implicitní převody.

Implicitní celočíselné převody

V jazyce F# 6 jsou 32bitová celá čísla rozšířena na 64bitová celá čísla, pokud jsou oba typy známé. Představte si například typický tvar rozhraní API:

type Tensor(…) =
    static member Create(sizes: seq<int64>) = Tensor(…)

V jazyce F# 5 musí být použity celočíselné literály pro int64:

Tensor.Create([100L; 10L; 10L])

nebo

Tensor.Create([int64 100; int64 10; int64 10])

V jazyce F# 6 dochází k rozšíření automaticky, int32 aby bylo int64int32 při odvozování typu typ zdroje i cíle známo, že až nativeintdo a int32 dodouble. V případech, jako jsou předchozí příklady, int32 se tedy dají použít literály:

Tensor.Create([100; 10; 10])

I přes tuto změnu jazyk F# ve většině případů používá explicitní rozšíření číselných typů. Implicitní rozšíření se například nevztahuje na jiné číselné typy, jako int8int16jsou nebo nebo od float32 do float64, nebo v případě, že je neznámý zdroj nebo cílový typ. Volitelně můžete také povolit, aby se upozornění /warnon:3389 zobrazovala v každém bodě implicitního rozšíření čísel, jak je popsáno v volitelných upozorněních pro implicitní převody.

Prvotřídní podpora pro . Implicitní převody ve stylu NET

V jazyce F# 6 se při volání metod automaticky použijí převody op_Implicit .NET v kódu jazyka F#. Například v jazyce F# 5 bylo nutné použít XName.op_Implicit při práci s rozhraními .NET API pro XML:

open System.Xml.Linq
let purchaseOrder = XElement.Load("PurchaseOrder.xml")
let partNos = purchaseOrder.Descendants(XName.op_Implicit "Item")

V jazyce F# 6 se pro výrazy argumentů automaticky použijí převody, op_Implicit pokud jsou typy dostupné pro zdrojový výraz a cílový typ:

open System.Xml.Linq
let purchaseOrder = XElement.Load("PurchaseOrder.xml")
let partNos = purchaseOrder.Descendants("Item")

Volitelně můžete povolit, aby se upozornění /warnon:3395 zobrazovala při každém rozšíření převodů bodů op_Implicit v argumentech metody, jak je popsáno v volitelných upozorněních pro implicitní převody.

Poznámka:

V prvním vydání F# 6 bylo toto číslo /warnon:3390upozornění . Kvůli konfliktu se číslo upozornění později aktualizovalo na /warnon:3395.

Volitelná upozornění pro implicitní převody

Převody řízené typem a implicitní převody můžou špatně pracovat s odvozováním typu a vést k tomu, že kód je obtížně srozumitelný. Z tohoto důvodu existují některá omezení rizik, která pomáhají zajistit, aby tato funkce nebyla v kódu jazyka F# zneužitá. Za prvé, zdrojový i cílový typ musí být silně znám, bez nejednoznačnosti nebo další odvození typu. Za druhé je možné aktivovat upozornění výslovného souhlasu, která hlásí jakékoli použití implicitních převodů, přičemž ve výchozím nastavení je zapnuté jedno upozornění:

  • /warnon:3388 (další implicitní upcast)
  • /warnon:3389 (implicitní numerické rozšíření)
  • /warnon:3391 (ve výchozím nastavení op_Implicit při argumentech bez metody)
  • /warnon:3395 (op_Implicit v argumentech metody)

Pokud váš tým chce zakázat všechna použití implicitních převodů, můžete také zadat /warnaserror:3388, , /warnaserror:3389, /warnaserror:3391a /warnaserror:3395.

Formátování binárních čísel

F# 6 přidá %B vzor do dostupných specifikátorů formátu pro binární formáty čísel. Zvažte následující kód jazyka F#:

printf "%o" 123
printf "%B" 123

Tento kód vytiskne následující výstup:

173
1111011

Tato funkce implementuje F# RFC FS-1100.

Zahodí při použití vazeb.

F# 6 umožňuje _ použití v vazbě use , například:

let doSomething () =
    use _ = System.IO.File.OpenText("input.txt")
    printfn "reading the file"

Tato funkce implementuje F# RFC FS-1102.

InlineIfLambda

Kompilátor jazyka F# obsahuje optimalizátor, který provádí vkládání kódu. V jazyce F# 6 jsme přidali novou deklarativní funkci, která umožňuje volitelně určit, že pokud je argument určen jako funkce lambda, měl by být tento argument vždy vložený na webech volání.

Představte si například následující iterateTwice funkci, která prochází polem:

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]

Pokud je web volání:

let arr = [| 1.. 100 |]
let mutable sum = 0
arr  |> iterateTwice (fun x ->
    sum <- sum + x)

Potom po vložení a dalších optimalizacích se kód stane:

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]

Na rozdíl od předchozích verzí jazyka F# se tato optimalizace použije bez ohledu na velikost zahrnutého výrazu lambda. Tuto funkci lze také použít k implementaci zrušení registrace smyčky a podobných transformací spolehlivěji.

Upozornění na vyjádření výslovného souhlasu (/warnon:3517ve výchozím nastavení vypnuto) je možné zapnout a indikovat místa v kódu, kde InlineIfLambda argumenty nejsou vázány na výrazy lambda na webech volání. V normálních situacích by toto upozornění nemělo být povolené. V některých typech vysokovýkonného programování ale může být užitečné zajistit, aby byl veškerý kód vložený a zploštěný.

Tato funkce implementuje F# RFC FS-1098.

Obnovitelný kód

Podpora task {…} F# 6 je založená na základech označovaných jako obnovitelný kódRFC FS-1087. Obnovitelný kód je technická funkce, která se dá použít k vytváření mnoha druhů vysoce výkonných asynchronních a výnosných stavových počítačů.

Další funkce kolekce

FSharp.Core 6.0.0 přidává pět nových operací do funkcí základní kolekce. Mezi tyto funkce patří:

  • List/Array/Seq.insertAt
  • List/Array/Seq.removeAt
  • List/Array/Seq.updateAt
  • List/Array/Seq.insertManyAt
  • List/Array/Seq.removeManyAt

Všechny tyto funkce provádějí operace kopírování a aktualizace odpovídajícího typu nebo sekvence kolekce. Tento typ operace je forma "funkční aktualizace". Příklady použití těchto funkcí najdete v odpovídající dokumentaci, například List.insertAt.

Představte si například model, zprávu a logiku aktualizace pro jednoduchou aplikaci "Seznam úkolů" napsanou ve stylu Elmish. Tady uživatel komunikuje s aplikací, generuje zprávy a update funkce zpracovává tyto zprávy a vytváří nový model:

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 }

Díky těmto novým funkcím je logika jasná a jednoduchá a spoléhá pouze na neměnná data.

Tato funkce implementuje F# RFC FS-1113.

Mapa obsahuje klíče a hodnoty

V FSharp.Core 6.0.0 Map teď typ podporuje vlastnosti Klíče a hodnoty . Tyto vlastnosti nekopírují podkladovou kolekci.

Tato funkce je zdokumentovaná v F# RFC FS-1113.

Další vnitřní objekty pro NativePtr

FSharp.Core 6.0.0 přidává nové vnitřní objekty do modulu NativePtr :

  • NativePtr.nullPtr
  • NativePtr.isNullPtr
  • NativePtr.initBlock
  • NativePtr.clear
  • NativePtr.copy
  • NativePtr.copyBlock
  • NativePtr.ofILSigPtr
  • NativePtr.toILSigPtr

Stejně jako u jiných funkcí jsou NativePtrtyto funkce vloženy a jejich použití generuje upozornění, pokud /nowarn:9 se nepoužívá. Použití těchto funkcí je omezeno na nespravované typy.

Tato funkce je zdokumentovaná v F# RFC FS-1109.

Další číselné typy s poznámkami jednotek

V jazyce F# 6 teď podporují následující typy nebo zkratky typů poznámky jednotek měr. Nové doplňky se zobrazují tučně:

Alias F# Typ 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

Můžete například anotovat celé číslo bez znaménka následujícím způsobem:

[<Measure>]
type days

let better_age = 3u<days>

Tato funkce je zdokumentovaná v F# RFC FS-1091.

Informační upozornění pro zřídka používané symbolické operátory

F# 6 přidává měkké pokyny, které denormalizují použití :=, !incr, a decr v jazyce F# 6 a novějším. Použití těchto operátorů a funkcí vytváří informační zprávy, které vás vyzve k nahrazení kódu explicitním použitím Value vlastnosti.

V programování jazyka F# lze referenční buňky použít pro proměnlivé registry přidělené haldou. I když jsou občas užitečné, jsou zřídka potřeba v moderním kódování jazyka F#, protože let mutable je možné je použít. Základní knihovna jazyka F# obsahuje dva operátory := a ! dvě funkce incr a decr konkrétně související s voláními odkazů. Přítomnost těchto operátorů znamená, že referenční buňky jsou pro programování jazyka F# centrálnější, než potřebují, což vyžaduje, aby tyto operátory znali všichni programátoři jazyka F#. ! Operátor může být navíc snadno zaměňován s not operací v jazyce C# a jinými jazyky, potenciálně drobným zdrojem chyb při překladu kódu.

Důvodem této změny je snížit počet operátorů, které potřebuje programátor F#, a zjednodušit tak F# pro začátečníky.

Představte si například následující kód F# 5:

let r = ref 0

let doSomething() =
    printfn "doing something"
    r := !r + 1

Za prvé, referenční buňky jsou zřídka potřeba v moderním kódování jazyka F#, jak let mutable je obvykle možné použít:

let mutable r = 0

let doSomething() =
    printfn "doing something"
    r <- r + 1

Pokud používáte odkazové buňky, F# 6 vygeneruje informační upozornění s výzvou, abyste změnili poslední řádek na r.Value <- r.Value + 1a propojí vás s dalšími pokyny k vhodnému použití referenčních buněk.

let r = ref 0

let doSomething() =
    printfn "doing something"
    r.Value <- r.Value + 1

Tyto zprávy nejsou varování; jsou "informační zprávy" zobrazené ve výstupu integrovaného vývojového prostředí a kompilátoru. Jazyk F# zůstává zpětně kompatibilní.

Tato funkce implementuje F# RFC FS-1111.

Nástroje F#: Výchozí nastavení pro skriptování v sadě Visual Studio .NET 6

Pokud otevřete nebo spustíte skript jazyka F# (.fsx) v sadě Visual Studio, skript se ve výchozím nastavení analyzuje a spustí pomocí rozhraní .NET 6 s 64bitovým spuštěním. Tato funkce byla ve verzi Preview v pozdějších verzích sady Visual Studio 2019 a teď je ve výchozím nastavení povolená.

Pokud chcete povolit skriptování rozhraní .NET Framework, vyberte Nástroje>Možnosti>F# Tools>F# Interactive. Nastavte možnost Použít skriptování .NET Core na false a restartujte okno F# Interactive. Toto nastavení má vliv na úpravy skriptu i spouštění skriptu. Pokud chcete povolit 32bitové spouštění skriptování rozhraní .NET Framework, nastavte také 64bitovou verzi F# Interactive na false. Pro skriptování .NET Core neexistuje žádná 32bitová možnost.

Nástroje jazyka F#: Připnutí verze sady SDK skriptů jazyka F#

Pokud skript spustíte v dotnet fsi adresáři obsahujícím soubor global.json s nastavením sady .NET SDK, použije se uvedená verze sady .NET SDK ke spuštění a úpravě skriptu. Tato funkce byla k dispozici v novějších verzích jazyka F# 5.

Předpokládejme například, že v adresáři existuje skript s následujícím souborem global.json , který určuje zásadu verze sady .NET SDK:

{
  "sdk": {
    "version": "5.0.200",
    "rollForward": "minor"
  }
}

Pokud teď spustíte skript pomocí dotnet fsitohoto adresáře, bude se respektovat verze sady SDK. Jedná se o výkonnou funkci, která umožňuje "uzamknout" sadu SDK používanou ke kompilaci, analýze a spouštění skriptů.

Pokud skript otevřete a upravíte v sadě Visual Studio a dalších prostředích IDE, bude toto nastavení při analýze a kontrole skriptu respektovat. Pokud se sada SDK nenajde, budete ji muset nainstalovat na vývojový počítač.

V systémech Linux a další systémy Unix můžete tuto možnost kombinovat se shebangem a určit také jazykovou verzi pro přímé spuštění skriptu. Jednoduchá shebang pro script.fsx :

#!/usr/bin/env -S dotnet fsi

printfn "Hello, world"

Nyní lze skript spustit přímo pomocí script.fsx. Můžete to zkombinovat s konkrétní, ne výchozí jazykovou verzí, například takto:

#!/usr/bin/env -S dotnet fsi --langversion:5.0

Poznámka:

Toto nastavení se ignoruje pomocí nástrojů pro úpravy, které analyzují skript za předpokladu, že se předpokládá nejnovější jazyková verze.

Odebrání starších funkcí

Od verze F# 2.0 už některé zastaralé funkce dlouho zobrazovaly upozornění. Použití těchto funkcí v jazyce F# 6 obsahuje chyby, pokud explicitně nepoužíváte /langversion:5.0. Mezi funkce, které poskytují chyby, patří:

  • Více obecných parametrů pomocí názvu typu přípony, například (int, int) Dictionary. To se stane chybou v F# 6. Místo toho by se měla použít standardní syntaxe Dictionary<int,int> .
  • #indent "off". Stane se to chybou.
  • x.(expr). Stane se to chybou.
  • module M = struct … end . Stane se to chybou.
  • Použití vstupů *.ml a *.mli. Stane se to chybou.
  • Použití nebo (*IF-CAML*)(*IF-OCAML*). Stane se to chybou.
  • Použití operátoru land, , lorlxor, lsl, lsrnebo asr jako operátory infixu. Jedná se o infixovaná klíčová slova v jazyce F#, protože byla infixovaná klíčová slova v OCaml a nejsou definována v FSharp.Core. Použití těchto klíčových slov teď vygeneruje upozornění.

Tím se implementuje F# RFC FS-1114.