Yang baru di C# 6

F# 6 menambahkan beberapa perbaikan pada bahasa F# dan F# Interactive. Ini dirilis dengan .NET 6.

Anda dapat mengunduh SDK .NET terbaru dari halaman unduhan .NET.

Memulai

F# 6 tersedia di semua distribusi .NET Core dan peralatan Visual Studio. Untuk informasi selengkapnya, lihat Memulai F#.

task {…}

F# 6 menyertakan dukungan asli untuk penulisan tugas .NET dalam kode F#. Misalnya, pertimbangkan kode F# berikut untuk membuat tugas yang kompatibel dengan .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

Menggunakan F#6, kode ini dapat ditulis ulang sebagai berikut.

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

Dukungan tugas tersedia untuk F# 5 melalui pustaka TaskBuilder.fs dan Ply yang luar biasa. Seharusnya mudah untuk memigrasikan kode ke dukungan bawaan. Namun, ada beberapa perbedaan: namespace layanan dan inferensi jenis sedikit berbeda antara dukungan bawaan dan pustaka ini, dan beberapa anotasi jenis tambahan mungkin diperlukan. Jika perlu, Anda masih dapat menggunakan pustaka komunitas ini dengan F# 6 jika Anda mereferensikannya secara eksplisit dan membuka namespace layanan yang benar di setiap file.

Menggunakan task {…} sangat mirip dengan menggunakan async {…}. Menggunakan task {…} memiliki beberapa keunggulan dibandingkan async {…}:

  • Overhead task {...} lebih rendah, mungkin meningkatkan performa di jalur kode panas di mana pekerjaan asinkron dijalankan dengan cepat.
  • Penelusuran kesalahan jejak loncatan dan tumpukan untuk task {…} lebih baik.
  • Berinteraksi dengan paket .NET yang mengharapkan atau menghasilkan tugas lebih mudah.

Jika Anda terbiasa dengan async {…}, ada beberapa perbedaan yang perlu diperhatikan:

  • task {…} segera menjalankan tugas ke titik tunggu pertama.
  • task {…} tidak secara implisit menyebarkan token pembatalan.
  • task {…} tidak melakukan pemeriksaan pembatalan implisit.
  • task {…} tidak mendukung tailcall asinkron. Ini berarti menggunakan return! .. secara rekursif dapat mengakibatkan luapan tumpukan jika tidak ada jeda asinkron yang mengganggu.

Secara umum, Anda harus mempertimbangkan untuk menggunakan task {…} di atas async {…} dalam kode baru jika Anda beroperasi dengan pustaka .NET yang menggunakan tugas, dan jika Anda tidak mengandalkan tailcall kode asinkron atau propagasi token pembatalan implisit. Dalam kode yang ada, Anda hanya boleh beralih ke task {…} setelah Anda meninjau kode untuk memastikan Anda tidak mengandalkan karakteristik async {…} yang disebutkan sebelumnya.

Fitur ini menerapkan F# RFC FS-1097.

Sintaksis pengindeksan yang lebih sederhana dengan expr[idx]

F# 6 memungkinkan sintaksis expr[idx] untuk mengindeks dan membagi kumpulan.

Hingga dan termasuk F# 5, F# telah menggunakan expr.[idx] sebagai sintaksis pengindeksan. Mengizinkan penggunaan expr[idx] didasarkan pada umpan balik berulang dari mereka yang mempelajari F# atau melihat F# untuk pertama kalinya bahwa penggunaan pengindeksan notasi titik dianggap sebagai penyimpangan yang tidak perlu dari praktik industri standar.

Ini bukan perubahan yang melanggar karena secara default, tidak ada peringatan yang dikeluarkan pada penggunaan expr.[idx]. Namun, beberapa pesan informasi yang menyarankan klarifikasi kode dikeluarkan. Anda secara opsional juga dapat mengaktifkan pesan informasi lebih lanjut. Misalnya, Anda dapat mengaktifkan peringatan informasi opsional (/warnon:3566) untuk mulai melaporkan penggunaan notasi expr.[idx]. Untuk informasi selengkapnya, lihat Notasi Pengindeks.

Dalam kode baru, kami menyarankan penggunaan sistematis expr[idx] sebagai sintaksis pengindeksan.

Fitur ini menerapkan F# RFC FS-1110.

Representasi struktur untuk pola aktif parsial

F# 6 menambah fitur "pola aktif" dengan representasi struktur opsional untuk pola aktif parsial. Ini memungkinkan Anda menggunakan atribut untuk membatasi pola aktif parsial untuk mengembalikan opsi nilai:

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

Penggunaan atribut diperlukan. Di situs penggunaan, kode tidak berubah. Hasil akhirnya adalah alokasi berkurang.

Fitur ini menerapkan F# RFC FS-1039.

Operasi kustom yang kelebihan beban dalam ekspresi komputasi

F# 6 memungkinkan Anda menggunakan CustomOperationAttribute pada metode yang kelebihan beban.

Pertimbangkan penggunaan berikut dari penyusun ekspresi komputasi 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"
    }

Di sini operasi kustom body mengambil sejumlah argumen dari berbagai jenis. Hal ini didukung oleh penerapan penyusun berikut, yang menggunakan overloading:

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

Fitur ini menerapkan F# RFC FS-1056.

Pola “as”

Di F# 6, sisi kanan dari sebuah pola as sekarang dapat menjadi sebuah pola. Ini penting ketika pengujian jenis telah memberikan jenis yang lebih kuat ke input. Sebagai contoh, perhatikan kode berikut:

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)

Dalam setiap kasus pola, objek input diuji jenisnya. Sisi kanan dari pola as sekarang diperbolehkan menjadi pola lebih lanjut, yang dengan sendirinya dapat mencocokkan objek pada jenis yang lebih kuat.

Fitur ini menerapkan F# RFC FS-1105.

Revisi sintaksis indentasi

F# 6 menghapus sejumlah inkonsistensi dan batasan dalam penggunaan sintaksis yang sadar indentasi. Lihat RFC FS-1108. Ini menyelesaikan 10 masalah signifikan yang disorot oleh pengguna F# sejak F# 4.0.

Misalnya, dalam F# 5 kode berikut diizinkan:

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

Namun, kode berikut tidak diizinkan (menghasilkan peringatan):

let c = [
    1
    2
]

Di F# 6, keduanya diizinkan. Ini membuat F# lebih sederhana dan lebih mudah dipelajari. Kontributor komunitas F# Hadrian Tang telah memimpin dalam hal ini, termasuk pengujian sistematis fitur yang luar biasa dan sangat berharga.

Fitur ini menerapkan F# RFC FS-1108.

Konversi implisit tambahan

Di F# 6, kami telah mengaktifkan dukungan untuk konversi “implisit” dan “diarahkan ke jenis” tambahan, seperti yang dijelaskan dalam RFC FS-1093.

Perubahan ini membawa tiga keuntungan:

  1. Diperlukan lebih sedikit upcast eksplisit
  2. Lebih sedikit konversi bilangan bulat eksplisit diperlukan
  3. Dukungan kelas satu untuk konversi implisit gaya .NET ditambahkan

Fitur ini menerapkan F# RFC FS-1093.

Konversi upcast implisit tambahan

F# 6 menerapkan konversi upcast implisit tambahan. Misalnya, di F# 5 dan versi sebelumnya, upcast diperlukan untuk ekspresi pengembalian saat menerapkan fungsi yang ekspresinya memiliki subjenis yang berbeda pada cabang yang berbeda, bahkan saat ada anotasi jenis. Perhatikan kode F#5 berikut:

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

Di sini cabang dari perhitungan bersyarat masing-masing TextReader dan StreamReader, dan upcast ditambahkan untuk membuat kedua cabang memiliki jenis StreamReader. Di F# 6, upcast ini sekarang ditambahkan secara otomatis. Ini berarti kodenya lebih sederhana:

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

Anda dapat secara opsional mengaktifkan peringatan /warnon:3388 untuk menampilkan peringatan di setiap titik, upcast implisit tambahan digunakan, seperti yang dijelaskan dalam Peringatan opsional untuk konversi implisit.

Konversi bilangan bulat implisit

Dalam F# 6, bilangan bulat 32-bit diperluas menjadi bilangan bulat 64-bit ketika kedua jenis diketahui. Misalnya, pertimbangkan bentuk API yang khas:

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

Dalam F# 5, harfiah bilangan bulat untuk int64 harus digunakan:

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

or

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

Dalam F# 6, pelebaran terjadi secara otomatis untuk int32 ke int64, int32 ke nativeint, dan int32 ke double, ketika jenis sumber dan tujuan diketahui selama inferensi jenis. Jadi dalam kasus seperti contoh sebelumnya, harfiah int32 dapat digunakan:

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

Terlepas dari perubahan ini, F# terus menggunakan pelebaran eksplisit jenis numerik dalam banyak kasus. Misalnya, pelebaran implisit tidak berlaku untuk jenis numerik lainnya, seperti int8 atau int16, atau dari float32 ke float64, atau jika jenis sumber atau tujuan tidak diketahui. Anda juga dapat secara opsional mengaktifkan peringatan /warnon:3389 untuk menampilkan peringatan di setiap titik pelebaran numerik implisit digunakan, seperti yang dijelaskan dalam Peringatan opsional untuk konversi implisit.

Dukungan kelas satu untuk konversi implisit gaya .NET

Dalam F# 6, konversi "op_Implicit" .NET diterapkan secara otomatis dalam kode F# saat memanggil metode. Misalnya, di F# 5 perlu menggunakan XName.op_Implicit saat bekerja dengan .NET API untuk XML:

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

Di F# 6, op_Implicit konversi diterapkan secara otomatis untuk ekspresi argumen saat jenis tersedia untuk ekspresi sumber dan jenis target:

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

Anda dapat secara opsional mengaktifkan peringatan /warnon:3395 untuk menampilkan peringatan di setiap titik pelebaran konversi op_Implicit digunakan pada argumen metode, seperti yang dijelaskan dalam Peringatan opsional untuk konversi implisit.

Catatan

Pada rilis pertama F# 6, nomor peringatan ini adalah /warnon:3390. Karena konflik, nomor peringatan kemudian diperbarui menjadi /warnon:3395.

Peringatan opsional untuk konversi implisit

Konversi yang diarahkan ke jenis dan implisit dapat berinteraksi secara buruk dengan inferensi jenis dan mengarah ke kode yang lebih sulit untuk dipahami. Untuk alasan ini, ada beberapa mitigasi untuk membantu memastikan fitur ini tidak disalahgunakan dalam kode F#. Pertama, jenis sumber dan tujuan harus diketahui dengan kuat, tanpa menimbulkan ambiguitas atau inferensi jenis tambahan. Kedua, peringatan keikutsertaan dapat diaktifkan untuk melaporkan penggunaan konversi implisit apa pun, dengan satu peringatan aktif secara default:

  • /warnon:3388 (upcast implisit tambahan)
  • /warnon:3389 (pelebaran numerik implisit)
  • /warnon:3391 (op_Implicit pada argumen non-metode, aktif secara default)
  • /warnon:3395 (op_Implicit pada argumen metode)

Jika tim Anda ingin melarang semua penggunaan konversi implisit, Anda juga dapat menentukan /warnaserror:3388, /warnaserror:3389, /warnaserror:3391, dan /warnaserror:3395.

Memformat untuk bilangan biner

F# 6 menambahkan pola %B ke penentu format yang tersedia untuk format bilangan biner. Perhatikan kode F# berikut:

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

Kode ini mencetak output berikut:

173
1111011

Fitur ini menerapkan F# RFC FS-1100.

Membuang pengikatan penggunaan

F# 6 memungkinkan _ untuk digunakan dalam pengikatan use, misalnya:

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

Fitur ini menerapkan F# RFC FS-1102.

InlineIfLambda

Kompilator F# menyertakan pengoptimal yang melakukan inlining kode. Di F# 6 kami telah menambahkan fitur deklaratif baru yang memungkinkan kode untuk secara opsional menunjukkan bahwa, jika argumen ditentukan sebagai fungsi lambda, argumen itu sendiri harus selalu disisipkan di situs panggilan.

Misalnya, pertimbangkan fungsi iterateTwice berikut untuk melintasi array:

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]

Jika situs panggilan adalah:

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

Kemudian setelah inlining dan optimasi lainnya, kodenya menjadi:

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]

Tidak seperti versi F# sebelumnya, pengoptimalan ini diterapkan terlepas dari ukuran ekspresi lambda yang terlibat. Fitur ini juga dapat digunakan untuk menerapkan loop unrolling dan transformasi serupa dengan lebih andal.

Peringatan keikutsertaan (/warnon:3517, nonaktif secara default) dapat diaktifkan untuk menunjukkan tempat dalam kode Anda di mana argumen InlineIfLambda tidak terikat dengan ekspresi lambda di situs panggilan. Dalam situasi normal, peringatan ini tidak boleh diaktifkan. Namun, dalam beberapa jenis pemrograman performa tinggi, akan berguna untuk memastikan semua kode sejajar dan diratakan.

Fitur ini menerapkan F# RFC FS-1098.

Kode yang dapat dilanjutkan

Dukungan task {…} dari F# 6 dibangun di atas dasar yang disebut kode yang dapat dilanjutkanRFC FS-1087. Kode yang dapat dilanjutkan adalah fitur teknis yang dapat digunakan untuk membangun berbagai jenis mesin status asinkron dan menangguhkan performa tinggi.

Fungsi kumpulan tambahan

FSharp.Core 6.0.0 menambahkan lima operasi baru ke fungsi kumpulan core. Fungsi-fungsi ini adalah:

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

Semua fungsi ini melakukan operasi salin-dan-perbarui pada jenis atau urutan kumpulan yang sesuai. Jenis operasi ini adalah bentuk “pembaruan fungsional”. Untuk contoh penggunaan fungsi ini, lihat dokumentasi terkait, misalnya, List.insertAt.

Sebagai contoh, pertimbangkan model, pesan, dan logika pembaruan untuk aplikasi "Daftar Agenda" sederhana yang ditulis dalam gaya Elmish. Di sini pengguna berinteraksi dengan aplikasi, menghasilkan pesan, dan fungsi update memproses pesan-pesan ini, menghasilkan model baru:

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 }

Dengan fungsi-fungsi baru ini, logikanya jelas dan sederhana dan hanya bergantung pada data yang tidak dapat diubah.

Fitur ini menerapkan F# RFC FS-1113.

Peta memiliki Kunci dan Nilai

Di FSharp.Core 6.0.0, jenis Map sekarang mendukung properti Kunci dan Nilai. Properti ini tidak menyalin kumpulan yang mendasarinya.

Fitur ini didokumentasikan dalam F# RFC FS-1113.

Intrinsik tambahan untuk NativePtr

FSharp.Core 6.0.0 menambahkan intrinsik baru ke modul NativePtr:

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

Seperti fungsi lainnya di NativePtr, fungsi-fungsi ini sebaris, dan penggunaannya mengeluarkan peringatan kecuali /nowarn:9 digunakan. Penggunaan fungsi-fungsi ini dibatasi untuk jenis yang tidak dikelola.

Fitur ini didokumentasikan dalam F# RFC FS-1109.

Jenis numerik tambahan dengan anotasi unit

Di F# 6, jenis atau alias singkatan jenis berikut sekarang mendukung anotasi satuan ukuran. Tambahan baru ditampilkan dalam huruf tebal:

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

Misalnya, Anda dapat membuat anotasi bilangan bulat tidak bertanda sebagai berikut:

[<Measure>]
type days

let better_age = 3u<days>

Fitur ini didokumentasikan dalam F# RFC FS-1091.

Peringatan informasi untuk operator simbolis yang jarang digunakan

F# 6 menambahkan panduan mudah yang mendenormalisasi penggunaan :=, !, incr, dan decr di F# 6 dan seterusnya. Menggunakan operator dan fungsi ini menghasilkan pesan informasi yang meminta Anda untuk mengganti kode Anda dengan penggunaan eksplisit properti Value.

Dalam pemrograman F#, sel referensi dapat digunakan untuk register yang dapat diubah dengan alokasi timbunan. Meskipun terkadang berguna, sel referensi tersebut jarang dibutuhkan dalam pengodean F# modern, karena let mutable dapat digunakan sebagai gantinya. Pustaka core F# mencakup dua operator := dan ! dan dua fungsi incr dan decr yang secara khusus terkait dengan panggilan referensi. Adanya operator-operator ini membuat sel referensi menjadi lebih terpusat dalam pemrograman F# daripada yang seharusnya, mengharuskan semua programmer F# untuk mengetahui operator-operator ini. Lebih lanjut, operator ! dapat dengan mudah dikacaukan dengan operasi not dalam C# dan bahasa lain, yang berpotensi menjadi sumber bug yang kurang terlihat saat menerjemahkan kode.

Alasan perubahan ini adalah untuk mengurangi jumlah operator yang perlu diketahui oleh programmer F#, dan dengan demikian menyederhanakan F# untuk pemula.

Sebagai contoh, perhatikan kode F#5 berikut:

let r = ref 0

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

Pertama, sel referensi jarang diperlukan dalam pengodean F# modern, karena let mutable biasanya dapat digunakan sebagai gantinya:

let mutable r = 0

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

Jika Anda menggunakan sel referensi, F# 6 mengeluarkan peringatan informasi yang meminta Anda untuk mengubah baris terakhir ke r.Value <- r.Value + 1, dan menautkan Anda ke panduan lebih lanjut tentang penggunaan sel referensi yang sesuai.

let r = ref 0

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

Pesan-pesan ini bukan peringatan; pesan tersebut adalah "pesan informasi" yang ditampilkan dalam IDE dan output kompilator. F# tetap kompatibel versi lama.

Fitur ini menerapkan F# RFC FS-1111.

Peralatan F#: .NET 6 default untuk pembuatan skrip di Visual Studio

Jika Anda membuka atau menjalankan Skrip F# (.fsx) di Visual Studio, secara default skrip akan dianalisis dan dijalankan menggunakan .NET 6 dengan eksekusi 64-bit. Fungsionalitas ini dalam pratinjau dalam rilis Visual Studio 2019 yang lebih baru dan sekarang diaktifkan secara default.

Untuk mengaktifkan pembuatan skrip .NET Framework, pilih Alat>Opsi>Alat F#>F# Interactive. Atur Gunakan Pembuatan Skrip .NET Core ke false, lalu hidupkan ulang jendela F# Interactive. Pengaturan ini memengaruhi pengeditan skrip dan eksekusi skrip. Untuk mengaktifkan eksekusi 32-bit untuk skrip .NET Framework, atur juga F# Interactive 64-bit ke false. Tidak ada opsi 32-bit untuk skrip .NET Core.

Peralatan F#: Menyematkan versi SDK dari skrip F# Anda

Jika Anda menjalankan skrip menggunakan dotnet fsi dalam direktori yang berisi file global.json dengan pengaturan SDK .NET, versi SDK .NET yang tercantum akan digunakan untuk menjalankan dan mengedit skrip. Fitur ini telah tersedia di versi F# 5 yang lebih baru.

Misalnya, asumsikan ada skrip di direktori dengan file global.json berikut yang menentukan kebijakan versi SDK .NET:

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

Jika sekarang Anda menjalankan skrip menggunakan dotnet fsi, dari direktori ini, versi SDK akan dipatuhi. Ini adalah fitur canggih yang memungkinkan Anda "mengunci" SDK yang digunakan untuk mengompilasi, menganalisis, dan menjalankan skrip Anda.

Jika Anda membuka dan mengedit skrip Anda di Visual Studio dan IDE lainnya, peralatan akan mematuhi pengaturan ini saat menganalisis dan memeriksa skrip Anda. Jika SDK tidak ditemukan, Anda harus menginstalnya di komputer pengembangan Anda.

Di Linux dan sistem Unix lainnya, Anda dapat menggabungkan ini dengan shebang untuk juga menentukan versi bahasa untuk eksekusi langsung skrip. Shebang sederhana untuk script.fsx adalah:

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

printfn "Hello, world"

Sekarang skrip dapat dijalankan langsung dengan script.fsx. Anda dapat menggabungkan ini dengan versi bahasa non-default tertentu seperti ini:

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

Catatan

Pengaturan ini diabaikan oleh alat pengeditan, yang akan menganalisis skrip dengan asumsi versi bahasa terbaru.

Menghapus fitur lama

Sejak F# 2.0, beberapa fitur lama yang tidak digunakan lagi telah lama memberikan peringatan. Menggunakan fitur ini di F# 6 memberikan kesalahan kecuali Anda secara eksplisit menggunakan /langversion:5.0. Fitur yang memberikan kesalahan adalah:

  • Beberapa parameter generik menggunakan nama jenis postfix, misalnya (int, int) Dictionary. Ini menjadi kesalahan di F# 6. Sintaks standar Dictionary<int,int> harus digunakan sebagai gantinya.
  • #indent "off". Ini menjadi kesalahan.
  • x.(expr). Ini menjadi kesalahan.
  • module M = struct … end . Ini menjadi kesalahan.
  • Penggunaan input *.ml dan *.mli. Ini menjadi kesalahan.
  • Penggunaan (*IF-CAML*) atau (*IF-OCAML*). Ini menjadi kesalahan.
  • Penggunaan land, lor, lxor, lsl, lsr, or asr sebagai operator infiks. Ini adalah kata kunci infiks di F# karena merupakan kata kunci infiks di OCaml dan tidak ditentukan di FSharp.Core. Menggunakan kata kunci ini sekarang akan mengeluarkan peringatan.

Ini menerapkan F# RFC FS-1114.