1 điểm bởi GN⁺ 2024-11-11 | 1 bình luận | Chia sẻ qua WhatsApp
  • F# 9, đi kèm .NET 9, giảm các vấn đề an toàn phát sinh khi tương tác C#/.NET nhờ kiểu tham chiếu nullable và cải thiện chẩn đoán của trình biên dịch
  • Các tính năng như thuộc tính .Is* cho discriminated union, partial active pattern trả về bool, computation expression rỗng giúp cú pháp F# hằng ngày ngắn gọn hơn
  • FSharp.Core bổ sung các hàm ngẫu nhiên cho collection và hỗ trợ collection expression của C#, giúp collection bất biến của F# dễ dùng hơn trong mã .NET khác
  • Trình biên dịch phát hiện sớm hơn các vấn đề như dùng attribute sai, phương thức IL vượt quá 65.520, và khả năng hiển thị của private member
  • Nhờ tối ưu kiểm tra equality, phạm vi số nguyên, list/array comprehension, một số vòng lặp nhanh hơn 1,25×~8×, và một số array comprehension nhanh hơn tới 10×

F# 9 được cung cấp trong .NET 9

  • F# 9 bao gồm các thay đổi nhằm giúp chương trình an toàn hơn, bền bỉ hơn và có hiệu năng tốt hơn
  • Có thể dùng trong .NET 9, và SDK .NET mới nhất có thể tải từ trang tải xuống .NET
  • Các thay đổi chính được phát triển tại kho mã nguồn mở F#

Thay đổi về tính năng ngôn ngữ

  • Kiểu tham chiếu nullable

    • F# được thiết kế để tránh null, nhưng khi dùng cùng các thư viện .NET viết bằng C#, null có thể xuất hiện
    • F# 9 biểu diễn một cách type-safe kiểu tham chiếu mà null là hợp lệ, như string | null
    • Nếu gán null vào string hoặc truy cập trực tiếp .Length trên giá trị string | null, cảnh báo về khả năng null sẽ xuất hiện
    • Nếu xử lý trước trường hợp null trong pattern matching, các binding sau đó được coi là giá trị non-null
    • Trong mã generic, để trả về null cần ràng buộc kiểu tham chiếu như 'T : not struct
    • Có thể xem thêm tại Nullable Reference Types in F# 9
  • Thuộc tính .Is* của discriminated union

    • Discriminated union có thuộc tính .Is* được tự động sinh cho từng case
    • Ví dụ, nếu kiểu Contact có các case EmailPhone, có thể kiểm tra có phải case cụ thể hay không bằng person.contact.IsEmail
    • Trước đây, để kiểm tra tương tự phải viết mã bằng biểu thức match như Email _ -> true | _ -> false
  • Partial active pattern trả về bool

    • Partial active pattern trước đây phải trả về Some () khi khớp thành công và None khi thất bại
    • Trong F# 9, cũng cho phép trả về bool
    • Trong ví dụ khớp chuỗi không phân biệt chữ hoa/thường, có thể trả về trực tiếp kết quả của String.Equals(..., StringComparison.OrdinalIgnoreCase)
  • Ưu tiên extension method khi có đối số

    • Một số thư viện .NET định nghĩa extension method có cùng tên với thuộc tính vốn có của kiểu
    • F# 9, để phù hợp với pattern này, sẽ phân giải thành extension method khi có đối số được cung cấp, thay vì báo lỗi type checking
    • Trong ví dụ, extension method X(f: Foo, i: int) cùng tên với thuộc tính X của Foo có thể được gọi ở dạng f.X(1), cho phép thiết lập thuộc tính và chaining lời gọi
  • Computation expression rỗng

    • F# 9 hỗ trợ computation expressions rỗng
    • seq { } tạo một sequence rỗng, và trong mã như HTML DSL có thể biểu diễn block rỗng như p { }
    • Computation expression rỗng dẫn tới lời gọi phương thức Zero của builder
    • Đây là cú pháp tự nhiên hơn so với builder { () } trước đây

Cải thiện hash directive và F# Interactive

  • Đối số hash directive không phải chuỗi

    • Trước đây, compiler hash directive chỉ cho phép đối số chuỗi được đặt trong dấu ngoặc kép
    • Trong F# 9, có thể nhận đối số thuộc kiểu bất kỳ
    • Có thể viết #nowarn 0070 thay cho #nowarn "0070", hoặc #time on thay cho #time "on"
  • #help mở rộng trong F# Interactive

    • Directive #help của F# Interactive hiển thị tài liệu của object hoặc function trong REPL
    • Có thể truyền đối số mà không cần dấu ngoặc kép
    • Ví dụ, #help List.map;; hiển thị mô tả, tham số, giá trị trả về, ví dụ, tên đầy đủ và thông tin assembly
    • Có thể xem thêm tại bài blog Enhancing #help in F# Interactive
  • Cho phép tiền tố FS trong #nowarn

    • Trước đây, nếu viết như #nowarn "FS0057", dù số cảnh báo đúng vẫn phát sinh lỗi Invalid warning number 'FS0057'
    • Trong F# 9, số cảnh báo vẫn được chấp nhận ngay cả khi có tiền tố FS
    • #nowarn 57, #nowarn 0057, #nowarn FS0057, cũng như dạng chuỗi "57", "0057", "FS0057" đều hoạt động
    • Trong một dự án, nên duy trì cùng một phong cách

Cải thiện an toàn và chẩn đoán của trình biên dịch

  • Cảnh báo vị trí [<TailCall>] không hợp lệ

    • F# 9 đưa ra cảnh báo nếu attribute [<TailCall>] được gắn vào vị trí không phù hợp
    • Ví dụ bao gồm khi gắn vào hàm không đệ quy, giá trị let binding, và giá trị recursive let binding
    • Những attribute này không ảnh hưởng đến hành vi mã, nhưng có thể gây nhầm lẫn cho người đọc
  • Tăng cường áp dụng AttributeTargets

    • Trình biên dịch thực thi đúng AttributeTargets trên let value, function, khai báo union case, constructor ngầm định, struct và class
    • Có thể ngăn các bug khó thấy, chẳng hạn quên đối số unit trong test Xunit
    • Trước đây, [<Fact>] let ``this test always fails`` = Assert.True(false) không phải là hàm thật nên bị test runner bỏ qua, và khi chạy dotnet test vẫn pass
    • Giờ đây sẽ phát sinh lỗi error FS0842: This attribute is not valid for use on this language element
  • Phục hồi parser

    • Nhờ cải thiện phục hồi parser, các tính năng công cụ như tô sáng cú pháp vẫn tiếp tục hoạt động ngay cả với mã chưa hoàn chỉnh về mặt cú pháp trong khi đang chỉnh sửa
    • Các đối tượng được phục hồi bao gồm pattern as chưa hoàn chỉnh, object expression, khai báo enum case, khai báo record, pattern primary constructor phức tạp, unresolved long identifier, nhánh match rỗng, và union case field hoặc field type bị thiếu
  • Độ chính xác của thông báo và vị trí chẩn đoán

    • F# 9 bổ sung thông báo chẩn đoán mới và vị trí chẩn đoán chính xác hơn
    • Các mục tiêu bao gồm override method mơ hồ trong object expression, abstract member trong non-abstract class, thuộc tính cùng tên với case của discriminated union, số lượng đối số active pattern không khớp, union có field trùng lặp, và việc dùng chung use! với and! trong computation expression
    • Class có hơn 65.520 phương thức trong IL được sinh ra sẽ gặp lỗi compile-time mới
    • Những class như vậy không thể được CLR load, dẫn tới lỗi runtime
  • Tùy chọn khả năng hiển thị thực

    • F# có đặc tính ghi private member vào IL dưới dạng internal, nên các dự án không phải F# có thể truy cập F# project thông qua InternalsVisibleTo và truy cập không phù hợp vào private member
    • F# 9 cung cấp compiler flag --realsig+ dưới dạng tùy chọn opt-in để sửa hành vi này
    • Có thể thêm <RealSig>true</RealSig> vào .fsproj để sử dụng
    • Có thể dùng để kiểm tra liệu solution có phụ thuộc vào hành vi cũ hay không

Thay đổi trong thư viện chuẩn FSharp.Core

  • Hàm ngẫu nhiên cho collection

    • Các module List, Array, Seq được bổ sung các hàm lấy mẫu ngẫu nhiên và xáo trộn
    • Việc dùng F# trở nên dễ hơn trong các kịch bản phổ biến cần tính ngẫu nhiên như khoa học dữ liệu, machine learning và phát triển game
    • Mọi hàm đều có ba biến thể
      • Biến thể dùng instance Random dùng chung, ngầm định và thread-safe
      • Biến thể nhận instance Random làm đối số
      • Biến thể nhận hàm randomizer tùy chỉnh phải trả về giá trị float từ 0.0 trở lên và nhỏ hơn 1.0
    • Các hàm được cung cấp là Shuffle, Choice, Choices, Sample, mỗi hàm có ba biến thể
    • Danh sách đầy đủ các hàm và biến thể có tại RFC #1135
  • Hành vi theo từng hàm ngẫu nhiên

    • Shuffle trả về collection mới cùng kiểu và cùng kích thước, trong đó mỗi item được xáo trộn với trọng số đồng đều theo độ dài collection
    • Với array, cũng có biến thể InPlace xáo trộn item ngay trong array hiện có
    • Choice trả về một phần tử ngẫu nhiên đơn lẻ với trọng số đồng đều theo kích thước collection
    • Choices chọn N phần tử từ collection đầu vào theo thứ tự ngẫu nhiên, và cùng một phần tử có thể được chọn nhiều lần
    • Sample chọn N phần tử từ collection đầu vào theo thứ tự ngẫu nhiên, nhưng không chọn cùng một phần tử hai lần
    • Với Sample, N không được lớn hơn độ dài collection
  • Constructor không đối số của CustomOperationAttribute

    • CustomOperationAttribute được bổ sung constructor không đối số, giúp việc tạo custom operation cho computation expression builder dễ hơn
    • Trong hầu hết trường hợp, tên tường minh giống với tên method, nên có thể dùng [<CustomOperation>] thay cho [<CustomOperation("bar")>]
  • Hỗ trợ collection expression của C#

    • Từ C#, có thể khởi tạo list và set của F# bằng collection expression
    • Ví dụ, có thể viết FSharpSet<int> mySet = [ 1, 2, 3 ]; thay cho SetModule.FromArray([1, 2, 3])
    • Collection bất biến của F# có thể được dùng khi cần structural equality mà collection trong System.Collections.Immutable không có

Cải thiện hiệu năng

  • Tối ưu kiểm tra equality

    • Kiểm tra equality nhanh hơn và giảm cấp phát bộ nhớ
    • Trong ví dụ tìm giá trị không tồn tại bằng Array.contains trên array của kiểu struct, trước đây xảy ra boxing 1.000 lần, nhưng giờ không còn boxing
    • Trong benchmark hàm array cho struct có 2 member, thời gian trung bình của ArrayContainsNonexisting giảm từ 5.190,95ns xuống 766,005ns, và cấp phát giảm từ 24.000B xuống 0
    • ArrayTryFindNonexisting giảm từ 5.139,58ns xuống 1.140,515ns, và cấp phát giảm từ 24.024B xuống 24B
    • Có thể xem thêm tại F# Developer Stories: How we’ve finally fixed a 9-year-old performance issue
  • Chia sẻ field trong struct discriminated union

    • Nếu nhiều case của struct discriminated union có field cùng tên và cùng kiểu, chúng có thể chia sẻ cùng vị trí bộ nhớ
    • Nhờ đó mức sử dụng bộ nhớ của struct giảm
    • Trong ví dụ, kích thước của struct discriminated union chia sẻ các field dựa trên cùng int64 là 16 byte
    • Phiên bản trước đây phải dùng tên field riêng cho từng case là 60 byte
    • Trước đây không cho phép cùng tên field, nên không có vấn đề tương thích nhị phân
  • Tối ưu phạm vi số nguyên

    • Trình biên dịch sinh mã tối ưu cho nhiều trường hợp hơn của biểu thức start..finishstart..step..finish
    • Trước đây, chỉ tối ưu khi kiểu là int/int32 và step là hằng số 1 hoặc -1
    • Các kiểu số nguyên khác và giá trị step khác dùng implementation kém hiệu quả dựa trên IEnumerable
    • Giờ đây tất cả các trường hợp này đều được tối ưu
    • Trong for … in start..finish do …, [start..step..finish], [for n in start..finish -> f n], tốc độ tăng từ 1,25× đến 8×
  • Tối ưu list và array comprehension

    • Dạng for x in xs -> … trong list và array comprehension được tối ưu
    • Cải thiện đặc biệt rõ ở array
    • Tốc độ tăng tối đa 10×, và kích thước cấp phát giảm còn từ một nửa đến một phần tư

Cải thiện công cụ Visual Studio

  • Bật mặc định live buffers

    • Tính năng live buffers của Visual Studio trước đây là opt-in, nhưng sau khi được kiểm thử đủ, đã được bật mặc định
    • Trình biên dịch nền vận hành IDE sử dụng buffer của file chưa lưu
    • Các thay đổi được áp dụng ngay cả khi file chưa được lưu xuống đĩa
    • Trước đây, khi rename symbol trong file đã chỉnh sửa nhưng chưa lưu, có thể xảy ra hành vi ngoài dự kiến
  • Code fix xóa dấu ngoặc không cần thiết

    • Visual Studio cung cấp code fix để xóa dấu ngoặc không cần thiết
    • Ví dụ, let f (x) = x có thể đổi thành let f x = x, và let _ = (2 * 2) + 3 thành let _ = 2 * 2 + 3
    • Đây là tính năng giúp giảm các trường hợp dấu ngoặc gần như chỉ là nhiễu, thay vì phục vụ sự rõ ràng
  • Hỗ trợ custom visualizer cho dự án F#

    • Debugger visualizer của Visual Studio cũng hoạt động trong các dự án F#
  • Signature tooltip ở giữa pipeline

    • Trước đây, nếu các tham số curried phức tạp đã được áp dụng cho hàm ở giữa pipeline, signature help không được cung cấp
    • Giờ đây signature tooltip cho tham số tiếp theo sẽ được hiển thị

1 bình luận

 
GN⁺ 2024-11-11
Các ý kiến trên Hacker News
  • F# đã luôn là ngôn ngữ tôi yêu thích nhất kể từ khi lần đầu tiếp xúc ở đại học
    Nó đi trước C# rất xa ở các tính năng như union, null safety, pattern matching, record, suy luận kiểu mạnh hơn và ràng buộc generic
    Việc C# dần đưa các tính năng này vào theo thời gian là điều tốt, nhưng đáng tiếc là chúng được đưa vào theo những cách không tương thích với nhau
    Do mức đầu tư cho F# nhỏ hơn C# rất nhiều nên có phần tụt lại về tốc độ đổi mới, nhưng đây vẫn là một ngôn ngữ tuyệt vời, nhìn chung tương thích với hệ sinh thái .NET và có thể đạt hiệu năng như C# với ít boilerplate hơn rất nhiều

    • Phần lớn các điểm không tương thích có thể tóm gọn ở source generators và các công cụ khác dựa trên sinh mã
      Có thể xử lý khá dễ bằng cách viết một dự án C# phụ chứa phần “mã keo” cần thiết
      Ngoài ra, tôi tò mò liệu có vấn đề cụ thể nào khác mà bạn đang nghĩ tới không
      Theo tôi biết, F# 9 cũng hỗ trợ việc dùng tham số generic ref struct mới được thêm vào C# gần đây, và còn có kế hoạch đưa vào các tính năng do chính F# định nghĩa
      Từ trước tới nay nó đã bắt kịp rất ấn tượng, và xứng đáng được công nhận nhiều hơn nữa
  • Đoạn “các lớp có hơn 65.520 phương thức trong IL được sinh ra sẽ gặp lỗi compile-time mới. Những lớp như vậy CLR không thể load được nên sẽ gây lỗi runtime” thật khó tưởng tượng nổi
    Dù sao thì F# là một ngôn ngữ tuyệt vời
    Tôi nghĩ đó là thứ tốt thứ hai Microsoft từng tạo ra sau Excel, và nó biến .NET thành một nền tảng hợp lý

    • Tôi cảm thấy C# khá bị đánh giá thấp
      Đây là ngôn ngữ tương đối dễ dạy cho những người đã quen JS hoặc TS, và cũng có năng suất cao
      Nó được dùng trong nhiều bối cảnh, từ game engine, backend doanh nghiệp đến ứng dụng desktop
      Tôi cho rằng Microsoft đã làm vài sai lầm ở giai đoạn đầu khiến tốc độ phát triển chậm lại, nhưng với vai trò một ngôn ngữ đa dụng thì nó thật sự tốt và cũng tương đối dễ học
    • Tôi tò mò bạn thấy nhược điểm của F# là gì
      Vài năm trước tôi từng thử qua một chút bằng một IDE nhẹ tên là LINQPad, nhưng sau đó không tiếp tục theo dõi ưu nhược điểm hay tình hình phát triển của nó
      https://www.linqpad.net/
  • Ở Phosphor, chúng tôi đã đưa ra một quyết định lớn, đặt cược định hướng công ty và công nghệ lên F# trong vài năm
    Sau hơn một năm thử nghiệm, chúng tôi đã viết lại hoàn toàn ứng dụng bằng TypeScript và Rust
    Sản phẩm chúng tôi đang xây dựng là công cụ lập trình cho người dùng cuối, nên ranh giới frontend/backend truyền thống trở nên mờ nhạt, và hệ sinh thái .NET không phù hợp lắm với việc này
    Ban đầu chúng tôi định dùng Fable để compile mã F# sang JS, Rust, .NET, v.v. nhằm duy trì type safety giữa nhiều công nghệ và thực hiện interop cần thiết
    Nhưng trên thực tế, interop giữa nhiều thư viện khó hơn dự kiến rất nhiều, và việc quản lý, cập nhật nhiều dependency cùng binding thật sự rất đau đớn
    Tôi vẫn nghĩ giả định rằng F# tạo ra mã đẹp và hiệu quả là đúng, nhưng xét về hệ sinh thái và cách thiết kế, nó chỉ phù hợp tốt với các ứng dụng có ranh giới frontend/backend truyền thống rõ ràng
    Trong những trường hợp đó, có lẽ F# sẽ chỉ được dùng ở backend
    Hai công nghệ tôi đang kỳ vọng nhất hiện nay là EffectMoonbit, những thứ chúng tôi đang dùng nội bộ
    Thư viện Schema của Effect lấp được nhiều khoảng trống trong hệ thống kiểu của TS, còn Moonbit trông giống một phiên bản F# hiện đại thoát khỏi phụ thuộc MS/.NET
    Moonbit được thiết kế bởi tác giả của ReScript, có thể xem là Fable cho OCaml; nó được thiết kế rất tốt và compile trực tiếp ra JS tối ưu hóa, WASM và output native
    Effect thì chúng tôi đang dùng trong môi trường production, còn Moonbit thì chưa, nhưng tiềm năng của nó với tư cách một ngôn ngữ được tạo ra cho thế giới ưu tiên AI là khá lớn

    • Việc compile mã F# và phơi bày nó dưới dạng module TypeScript là một trải nghiệm tốt
      Logic nghiệp vụ cốt lõi và các validator được viết bằng F#, phần còn lại của ứng dụng frontend viết bằng TypeScript, backend viết bằng C#
      Tức là chỉ đặt logic cốt lõi và phần validation trong F#, còn mọi đầu vào/đầu ra do TS và C# đảm nhiệm
    • Tôi tò mò liệu công ty đó có liên quan đến Darklang không
      Tôi nhớ đó là một sản phẩm tương tự và được viết bằng F#, nhưng gần đây tôi không theo dõi tình hình
      Effect khá tốt, và tôi ước nó cũng có ở các ngôn ngữ khác ngoài TypeScript
      MoonBit trông giống một ngôn ngữ lập trình độc quyền riêng, nên tôi hơi do dự khi chuyển sang đó thay vì một ngôn ngữ đã được biết đến rộng rãi; tôi tò mò bạn nhìn nhận điểm này thế nào
  • Tôi từng có một lớp mật mã học cho phép chọn bất kỳ ngôn ngữ nào dùng .NET, và bài làm bằng F# dễ đọc hơn hẳn so với của những người khác
    Tôi muốn dùng nó thường xuyên hơn, nhưng công việc khoa học dữ liệu gần như 100% là Python

  • F# 9 cũng được hưởng gần như toàn bộ các cải thiện hiệu năng của chính .NET 9
    Đặc biệt là các cải thiện về object escape analysis rất lớn
    https://devblogs.microsoft.com/dotnet/performance-improvemen...

  • Tôi thật sự nhớ khoảng thời gian làm việc với F#
    Đây là một ngôn ngữ có năng suất cao, nên chỉ việc tiếp tục theo dõi các bản cập nhật cũng đã thấy thú vị
    Xét đến quy mô cộng đồng và sự thờ ơ mà Microsoft đôi khi thể hiện, tôi nghĩ hỗ trợ công cụ của nó khá tốt
    Bất tiện lớn nhất là độ chính xác của code test coverage

  • Gần đây tôi có thử F# một chút, và từ góc nhìn của người đến từ Python thì tôi rất thích việc có thể thử nghiệm đủ thứ bằng REPL
    Không biết các lập trình viên F# có kinh nghiệm có dùng như vậy không
    Mùa đông này tôi muốn làm một dự án backend web nhỏ để tìm hiểu thêm về ngôn ngữ và hệ sinh thái
    Tôi nghe nói phía HTTP thì Oxpecker khá tốt, nhưng không biết có khuyến nghị nào cho client hay driver PostgreSQL không
    Tôi không thích ORM
    https://lanayx.github.io/Oxpecker/

    • Có hai khả năng
      https://monazita.gitlab.io/monazita/ là thứ được tạo ra cho dự án cá nhân trong lúc học F#, về cơ bản hoạt động được nhưng vẫn còn chỗ để trau chuốt thêm, và chỉ dành riêng cho PostgreSQL
      https://github.com/jacentino/DbFun được trau chuốt hơn dự án trước và hỗ trợ nhiều cơ sở dữ liệu
    • Npgsql là driver C# phổ biến và cũng có wrapper cho F#
      Có lẽ nên bắt đầu từ đó
    • Là một lập trình viên dùng nhiều ngôn ngữ và thỉnh thoảng có cơ hội dùng F#, tôi thực hiện phần lớn proof of concept bằng REPL
      Nếu chưa chắc về API, ngay cả trong codebase thực tế tôi cũng nhấn “Send to F# interactive” để chạy và thử nghiệm bên trong module
      Tôi cũng dùng nó để thử thư viện mới, benchmark nhanh, hoặc thay thế script PowerShell
      Có thể làm cho script F# chạy được bằng shebang #!/usr/bin/env -S dotnet fsi, nên tôi thường dùng nó như một lựa chọn thay cho bash/Python trong các script quanh dự án .NET đã cài sẵn dotnet-sdk
      Thường thì nó chạy nhanh hơn và nhìn chung cũng ngắn gọn tương đương
      Cảm nhận cá nhân là cú pháp và idiom của F# hợp với kiểu lập trình REPL ghép các đoạn code nhỏ lại hơn C#
      C# thường cần nhiều cấu trúc hướng đối tượng hơn
  • Tôi thắc mắc quản lý phiên bản của F# diễn ra như thế nào
    Có nhiều cải thiện chất lượng sống trông khá hay, nhưng xét theo semantic versioning thì không có phá vỡ tương thích nên việc đổi phiên bản chính có vẻ không chính đáng, và nếu dự án không dùng semantic versioning thì đây cũng có vẻ không phải là bước nhảy lớn về tính năng ngôn ngữ đến mức nâng từ 8 lên 9
    Ở bình luận khác có nhắc đến .NET 9 mới ra gần đây, nên tôi tự hỏi có phải là để đi cùng số phiên bản .NET không

    • .NET và C# dường như đã chuyển sang phát hành hằng năm, mỗi năm tăng một số, từ khoảng gần đây, và F# có vẻ cũng theo cách đó
      Tôi không biết họ cố ý chuyển vào thời điểm khớp với phiên bản .NET hay chỉ là trùng hợp
      Ví dụ C# đã phát hành C# 13 tương ứng với .NET 9
    • Trong cả C# và F#, phiên bản .NET chỉ phiên bản công cụ build được dùng khi chạy dotnet build
      Nó bao gồm msbuild, compiler, các gói NuGet, v.v.
      Ví dụ nhóm F# có thể đã đưa ra thay đổi ngôn ngữ giữa 8 và 9, nhưng ngay cả nếu không làm vậy, họ vẫn có thể vì lý do nào đó phát hành thay đổi compiler hoặc msbuild cần .NET 9
      Nếu không phải chờ môi trường triển khai cài .NET mới nhất, lập trình viên thường chỉ cần nâng code lên phiên bản runtime mới nhất
      Ngày nay nhu cầu đó cũng ít hơn nhờ các thay đổi MSBuild giúp tạo bản triển khai self-contained, nhưng đây vẫn là điều đáng biết
    • Phiên bản .NET mới ra hằng năm, và phiên bản C# cùng F# cũng khớp với bản hằng năm đó
      Chỉ là C# đi trước 4 số
      Dù sao thì tôi cũng nghĩ semantic versioning bị đánh giá quá cao
  • Tôi thắc mắc tình trạng của F# như một lựa chọn thay thế C# khi làm ứng dụng GUI trên Windows hiện ra sao
    Cũng tò mò không biết có công ty nào dùng F# cho mục đích này không

  • Tôi chưa từng trực tiếp thử F#, nhưng khi xem qua thì tài liệu này trông rất tuyệt: https://fsharpforfunandprofit.com/

    • Với người mới tiếp cận F#, đây thực sự là một trong những trang tốt nhất
      Nó cũng tốt cho lập trình viên C# giàu kinh nghiệm lẫn người tương đối mới học lập trình
      Dạo này trang gần như không được cập nhật nên khó tìm thảo luận về tính năng mới của F# 9, nhưng các bài viết hiện có rất xuất sắc để hiểu những khái niệm như applybind