1 คะแนน โดย GN⁺ 2024-11-11 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • F# 9 ที่รวมอยู่ใน .NET 9 ลดปัญหาด้านความปลอดภัยที่เกิดจากการทำงานร่วมกันระหว่าง C#/.NET ด้วย nullable reference types และการปรับปรุง diagnostics ของคอมไพเลอร์
  • ไวยากรณ์ F# ที่ใช้ในชีวิตประจำวันกระชับขึ้นด้วยพร็อพเพอร์ตี .Is* ของ discriminated union, partial active pattern ที่คืนค่า bool, computation expression แบบว่าง ฯลฯ
  • FSharp.Core เพิ่มฟังก์ชันสุ่มสำหรับคอลเลกชันและการรองรับ collection expressions ของ C# ทำให้ใช้ คอลเลกชันแบบ immutable ของ F# ในโค้ด .NET อื่นได้ง่ายขึ้น
  • คอมไพเลอร์แสดงปัญหาได้เร็วขึ้น เช่น การใช้ attribute ผิด, เมธอด IL เกิน 65,520 รายการ, visibility ของ private member
  • ด้วยการปรับปรุง equality check, ช่วงจำนวนเต็ม และการ optimize list/array comprehension บางลูปเร็วขึ้น 1.25×~8× และ array comprehension บางกรณีเร็วขึ้นได้ถึง 10×

F# 9 ที่มาพร้อม .NET 9

  • F# 9 มีการเปลี่ยนแปลงเพื่อทำให้โปรแกรมปลอดภัยขึ้น ทนทานขึ้น และมีประสิทธิภาพดีขึ้น
  • ใช้งานได้ใน .NET 9 และสามารถดาวน์โหลด .NET SDK ล่าสุดได้จากหน้าดาวน์โหลด .NET
  • การเปลี่ยนแปลงหลักพัฒนาอยู่ใน F# open source code repository

การเปลี่ยนแปลงฟีเจอร์ภาษา

  • Nullable reference types

    • F# ถูกออกแบบมาให้หลีกเลี่ยง null แต่เมื่อใช้งานร่วมกับไลบรารี .NET ที่เขียนด้วย C# อาจมี null เข้ามาได้
    • F# 9 แสดง reference type ที่ null เป็นค่าที่ถูกต้อง ได้อย่าง type-safe เช่น string | null
    • หากใส่ null ลงใน string หรือเข้าถึง .Length โดยตรงจากค่า string | null จะเกิดคำเตือนเรื่องความเป็นไปได้ของ null
    • เมื่อจัดการเคส null ก่อนใน pattern matching binding หลังจากนั้นจะถูกถือว่าเป็นค่าที่ไม่ใช่ null
    • ในโค้ด generic หากต้องการคืนค่า null จำเป็นต้องมี constraint ของ reference type เช่น 'T : not struct
    • ดูรายละเอียดได้ที่ Nullable Reference Types in F# 9
  • พร็อพเพอร์ตี .Is* ของ discriminated union

    • discriminated union มี พร็อพเพอร์ตี .Is* ที่สร้างให้อัตโนมัติสำหรับแต่ละเคส
    • ตัวอย่างเช่น หากชนิด Contact มีเคส Email และ Phone สามารถตรวจสอบว่าเป็นเคสใดเคสหนึ่งได้ด้วย person.contact.IsEmail
    • เดิมทีต้องเขียนโค้ดแบบ Email _ -> true | _ -> false ด้วยนิพจน์ match เพื่อทำการตรวจสอบเดียวกัน
  • partial active pattern ที่คืนค่า bool

    • partial active pattern เดิมต้องคืนค่า Some () เมื่อ match สำเร็จ และ None เมื่อไม่สำเร็จ
    • ใน F# 9 อนุญาตให้ คืนค่า bool ได้ด้วย
    • ในตัวอย่างการ match สตริงแบบไม่สนตัวพิมพ์เล็กใหญ่ สามารถคืนค่าผลลัพธ์ของ String.Equals(..., StringComparison.OrdinalIgnoreCase) ได้โดยตรง
  • ให้ความสำคัญกับ extension method เมื่อมีอาร์กิวเมนต์

    • ไลบรารี .NET บางตัวกำหนด extension method ที่มีชื่อเดียวกับพร็อพเพอร์ตีเดิมของชนิด
    • F# 9 ปรับให้เข้ากับแพตเทิร์นนี้ โดยเมื่อมีการส่งอาร์กิวเมนต์ จะ resolve เป็น extension method แทนที่จะล้มเหลวในการตรวจสอบชนิด
    • ในตัวอย่าง สามารถเรียก extension method X(f: Foo, i: int) ที่ชื่อเดียวกับพร็อพเพอร์ตี X ของ Foo ในรูปแบบ f.X(1) เพื่อกำหนดพร็อพเพอร์ตีและทำ call chaining ได้
  • computation expression แบบว่าง

    • F# 9 รองรับ computation expressions แบบว่าง
    • seq { } สร้าง sequence ว่าง และในโค้ดอย่าง HTML DSL สามารถแสดงบล็อกว่างเช่น p { } ได้
    • computation expression แบบว่างจะนำไปสู่การเรียก เมธอด Zero ของ builder
    • เป็นไวยากรณ์ที่เป็นธรรมชาติกว่า builder { () } แบบเดิม

การปรับปรุง hash directives และ F# Interactive

  • อาร์กิวเมนต์ของ hash directive ที่ไม่ใช่สตริง

    • compiler hash directive เดิมอนุญาตเฉพาะอาร์กิวเมนต์แบบสตริงที่ครอบด้วยเครื่องหมายคำพูด
    • ใน F# 9 สามารถรับ อาร์กิวเมนต์ชนิดใดก็ได้
    • สามารถเขียนเป็น #nowarn 0070 แทน #nowarn "0070" และ #time on แทน #time "on" ได้
  • #help ที่ขยายความสามารถใน F# Interactive

    • directive #help ของ F# Interactive แสดงเอกสารของอ็อบเจ็กต์หรือฟังก์ชันใน REPL
    • สามารถส่งอาร์กิวเมนต์โดยไม่ต้องใส่เครื่องหมายคำพูด
    • ตัวอย่างเช่น #help List.map;; จะแสดงคำอธิบาย พารามิเตอร์ ค่าที่คืน ตัวอย่าง ชื่อเต็ม และข้อมูล assembly
    • ดูรายละเอียดได้ที่ Enhancing #help in F# Interactive blog post
  • อนุญาต prefix FS ใน #nowarn

    • เดิมหากเขียนเช่น #nowarn "FS0057" จะเกิดข้อผิดพลาด Invalid warning number 'FS0057' แม้เลขคำเตือนจะถูกต้องก็ตาม
    • ใน F# 9 เลขคำเตือนจะถูกยอมรับแม้มี prefix FS
    • #nowarn 57, #nowarn 0057, #nowarn FS0057 รวมถึงรูปแบบสตริง "57", "0057", "FS0057" ใช้งานได้ทั้งหมด
    • ในโปรเจกต์ควรรักษาสไตล์เดียวกันไว้

การปรับปรุงความปลอดภัยและ diagnostics ของคอมไพเลอร์

  • คำเตือนตำแหน่ง [<TailCall>] ที่ไม่ถูกต้อง

    • F# 9 จะแจ้งเตือนเมื่อ attribute [<TailCall>] ถูกติดไว้ในตำแหน่งที่ไม่เหมาะสม
    • ตัวอย่างรวมถึงการติดไว้กับฟังก์ชันที่ไม่ recursive, ค่า let binding และค่า recursive let binding
    • attribute เหล่านี้ไม่ส่งผลต่อการทำงานของโค้ด แต่อาจทำให้ผู้อ่านสับสนได้
  • บังคับใช้ AttributeTargets เข้มงวดขึ้น

    • คอมไพเลอร์บังคับใช้ AttributeTargets อย่างถูกต้องกับค่า let, ฟังก์ชัน, การประกาศ union case, implicit constructor, struct และ class
    • ช่วยป้องกันบั๊กที่สังเกตเห็นได้ยาก เช่น การลืมอาร์กิวเมนต์ unit ในเทสต์ Xunit
    • เดิม [<Fact>] let ``this test always fails`` = Assert.True(false) ไม่ใช่ฟังก์ชันจริง จึงถูก test runner มองข้าม และเมื่อรัน dotnet test ก็ผ่าน
    • ตอนนี้จะเกิดข้อผิดพลาด error FS0842: This attribute is not valid for use on this language element
  • การกู้คืน parser

    • การปรับปรุง parser recovery ทำให้ฟีเจอร์ของเครื่องมืออย่าง syntax highlighting ยังคงทำงานได้แม้โค้ดระหว่างแก้ไขยังไม่สมบูรณ์ตามไวยากรณ์
    • สิ่งที่กู้คืนได้รวมถึงแพตเทิร์น as ที่ยังไม่สมบูรณ์, object expression, การประกาศ enum case, การประกาศ record, แพตเทิร์น primary constructor ที่ซับซ้อน, unresolved long identifier, match clause ว่าง, union case field และชนิดของ field ที่หายไป
  • ความแม่นยำของข้อความและตำแหน่ง diagnostics

    • F# 9 เพิ่มข้อความ diagnostics ใหม่และตำแหน่ง diagnostics ที่แม่นยำขึ้น
    • ครอบคลุม object expression ที่ override method กำกวม, abstract member ใน non-abstract class, พร็อพเพอร์ตีที่ชื่อเดียวกับเคสของ discriminated union, จำนวนอาร์กิวเมนต์ของ active pattern ไม่ตรงกัน, union ที่มี field ซ้ำ, การใช้ use! ร่วมกับ and! ใน computation expression เป็นต้น
    • คลาสที่มีเมธอดใน IL ที่สร้างขึ้น เกิน 65,520 รายการ จะเกิดข้อผิดพลาด compile-time ใหม่
    • คลาสเหล่านี้โหลดใน CLR ไม่ได้และจะนำไปสู่ข้อผิดพลาด runtime
  • ตัวเลือก visibility จริง

    • F# มีลักษณะที่บันทึก private member ใน IL เป็น internal ทำให้โปรเจกต์ที่ไม่ใช่ F# ซึ่งเข้าถึงโปรเจกต์ F# ได้ผ่าน InternalsVisibleTo สามารถเข้าถึง private member ได้อย่างไม่เหมาะสม
    • F# 9 มี compiler flag --realsig+ เป็นตัวเลือกแบบ opt-in เพื่อแก้พฤติกรรมนี้
    • ใน .fsproj สามารถเพิ่ม <RealSig>true</RealSig> เพื่อใช้งานได้
    • สามารถตรวจสอบได้ว่า solution พึ่งพาพฤติกรรมเดิมอยู่หรือไม่

การเปลี่ยนแปลงในไลบรารีมาตรฐาน FSharp.Core

  • ฟังก์ชันสุ่มสำหรับคอลเลกชัน

    • เพิ่มฟังก์ชัน สุ่มตัวอย่างและสับลำดับ ในโมดูล List, Array, Seq
    • ทำให้ใช้งาน F# ได้ง่ายขึ้นในสถานการณ์ทั่วไปที่ต้องการความสุ่ม เช่น data science, machine learning, การพัฒนาเกม
    • ทุกฟังก์ชันมีสามรูปแบบ
      • รูปแบบที่ใช้ instance Random ที่แชร์ร่วมกันแบบ implicit และ thread-safe
      • รูปแบบที่รับ instance Random เป็นอาร์กิวเมนต์
      • รูปแบบที่รับฟังก์ชัน randomizer แบบกำหนดเอง ซึ่งต้องคืนค่า float ตั้งแต่ 0.0 ขึ้นไปและน้อยกว่า 1.0
    • ฟังก์ชันที่มีให้คือ Shuffle, Choice, Choices, Sample รวมสี่ฟังก์ชัน และแต่ละฟังก์ชันมีสามรูปแบบ
    • ดูรายชื่อฟังก์ชันและรูปแบบทั้งหมดได้ที่ RFC #1135
  • พฤติกรรมของแต่ละฟังก์ชันสุ่ม

    • Shuffle คืนคอลเลกชันใหม่ที่มีชนิดและขนาดเดียวกัน โดยแต่ละรายการถูกสับด้วยน้ำหนักเท่ากันตามความยาวของคอลเลกชัน
    • สำหรับ array ยังมี รูปแบบ InPlace ที่สับรายการภายใน array เดิมด้วย
    • Choice คืนองค์ประกอบสุ่มหนึ่งรายการโดยมีน้ำหนักเท่ากันตามขนาดคอลเลกชัน
    • Choices เลือกองค์ประกอบ N รายการจากคอลเลกชันอินพุตตามลำดับสุ่ม และองค์ประกอบเดียวกันอาจถูกเลือกได้หลายครั้ง
    • Sample เลือกองค์ประกอบ N รายการจากคอลเลกชันอินพุตตามลำดับสุ่ม แต่จะไม่เลือกองค์ประกอบเดียวกันซ้ำ
    • ใน Sample ค่า N ต้องไม่มากกว่าความยาวของคอลเลกชัน
  • constructor แบบไม่มีอาร์กิวเมนต์ของ CustomOperationAttribute

    • เพิ่ม constructor แบบไม่มีอาร์กิวเมนต์ให้ CustomOperationAttribute ทำให้สร้าง custom operation ของ computation expression builder ได้ง่ายขึ้น
    • ในกรณีส่วนใหญ่ชื่อที่ระบุชัดเจนจะเหมือนกับชื่อเมธอด จึงสามารถใช้ [<CustomOperation>] แทน [<CustomOperation("bar")>] ได้
  • รองรับ collection expressions ของ C#

    • ใน C# สามารถ initialize list และ set ของ F# ด้วย collection expression ได้
    • ตัวอย่างเช่น เขียน FSharpSet<int> mySet = [ 1, 2, 3 ]; แทน SetModule.FromArray([1, 2, 3]) ได้
    • คอลเลกชัน immutable ของ F# ใช้ได้เมื่อต้องการ structural equality ที่ไม่มีในคอลเลกชันของ System.Collections.Immutable

การปรับปรุงประสิทธิภาพ

  • ปรับปรุง equality check

    • equality check เร็วขึ้นและลดการจัดสรรหน่วยความจำ
    • ตัวอย่างการค้นหาค่าที่ไม่มีอยู่ด้วย Array.contains ใน array ของชนิด struct เดิมมี boxing 1,000 ครั้ง แต่ตอนนี้ไม่มี boxing แล้ว
    • ใน benchmark ฟังก์ชัน array สำหรับ struct แบบ 2 สมาชิก เวลาเฉลี่ยของ ArrayContainsNonexisting ลดจาก 5,190.95ns เป็น 766.005ns และการจัดสรรลดจาก 24,000B เป็น 0
    • ArrayTryFindNonexisting ลดจาก 5,139.58ns เป็น 1,140.515ns และการจัดสรรลดจาก 24,024B เป็น 24B
    • ดูรายละเอียดได้ที่ F# Developer Stories: How we’ve finally fixed a 9-year-old performance issue
  • การแชร์ field ใน struct discriminated union

    • หากหลายเคสของ struct discriminated union มีชื่อ field และชนิด field เหมือนกัน สามารถแชร์ตำแหน่งหน่วยความจำเดียวกันได้
    • ส่งผลให้ การใช้หน่วยความจำ ของ struct ลดลง
    • ในตัวอย่าง ขนาดของ struct discriminated union ที่แชร์ field ฐาน int64 เดียวกันคือ 16 ไบต์
    • เวอร์ชันที่ต้องใช้ชื่อ field เฉพาะสำหรับแต่ละเคสเหมือนวิธีเดิมมีขนาด 60 ไบต์
    • เดิมไม่อนุญาตให้ใช้ชื่อ field เดียวกัน จึงไม่มีปัญหา binary compatibility
  • การ optimize ช่วงจำนวนเต็ม

    • คอมไพเลอร์สร้างโค้ดที่ optimize แล้วสำหรับกรณีของนิพจน์ start..finish และ start..step..finish ได้มากขึ้น
    • เดิมจะ optimize เฉพาะกรณีที่ชนิดเป็น int/int32 และ step เป็นค่าคงที่ 1 หรือ -1
    • ชนิดจำนวนเต็มอื่นและค่า step อื่นใช้ implementation บน IEnumerable ที่ไม่มีประสิทธิภาพ
    • ตอนนี้กรณีเหล่านี้ทั้งหมดได้รับการ optimize แล้ว
    • ใน for … in start..finish do …, [start..step..finish], [for n in start..finish -> f n] มีความเร็วเพิ่มขึ้นตั้งแต่ 1.25× ถึง 8×
  • การ optimize list และ array comprehension

    • รูปแบบ for x in xs -> … ใน list และ array comprehension ได้รับการ optimize
    • โดยเฉพาะใน array จะเห็นการปรับปรุงชัดเจน
    • ความเร็วเพิ่มขึ้นได้ถึง 10× และขนาดการจัดสรรลดลงเหลือครึ่งหนึ่งถึงหนึ่งในสี่

การปรับปรุงเครื่องมือ Visual Studio

  • เปิดใช้งาน live buffers เป็นค่าเริ่มต้น

    • ฟีเจอร์ live buffers ของ Visual Studio เคยเป็น opt-in แต่หลังจากทดสอบเพียงพอแล้วจึงเปิดใช้งานเป็นค่าเริ่มต้น
    • คอมไพเลอร์เบื้องหลังที่ขับเคลื่อน IDE ใช้ บัฟเฟอร์ไฟล์ที่ยังไม่ได้บันทึก
    • การเปลี่ยนแปลงจะมีผลแม้ยังไม่ได้บันทึกไฟล์ลงดิสก์
    • เดิมอาจเกิดพฤติกรรมไม่คาดคิดเมื่อ rename symbol ที่อยู่ในไฟล์ที่แก้ไขแล้วแต่ยังไม่ได้บันทึก
  • code fix ลบวงเล็บที่ไม่จำเป็น

    • Visual Studio มี code fix สำหรับลบวงเล็บที่ไม่จำเป็น
    • ตัวอย่างเช่น let f (x) = x สามารถเปลี่ยนเป็น let f x = x และ let _ = (2 * 2) + 3 เป็น let _ = 2 * 2 + 3
    • เป็นฟีเจอร์ที่ช่วยลดสิ่งรบกวนในกรณีที่วงเล็บไม่ได้มีไว้เพื่อความชัดเจน
  • รองรับ custom visualizer ในโปรเจกต์ F#

    • debugger visualizer ของ Visual Studio ทำงานได้ในโปรเจกต์ F# ด้วย
  • signature tooltip ระหว่าง pipeline

    • เดิม signature help จะไม่แสดงเมื่อพารามิเตอร์แบบ curried ที่ซับซ้อนถูก apply ไปแล้วกับฟังก์ชันกลาง pipeline
    • ตอนนี้จะแสดง signature tooltip สำหรับพารามิเตอร์ถัดไป

1 ความคิดเห็น

 
GN⁺ 2024-11-11
ความคิดเห็นจาก Hacker News
  • F# เป็นภาษาที่ชอบที่สุดมาตลอดนับตั้งแต่ได้รู้จักครั้งแรกในมหาวิทยาลัย
    มันล้ำหน้า C# ไปมากในด้านฟีเจอร์อย่าง discriminated unions, null safety, pattern matching, records, การอนุมานชนิดข้อมูลที่ทรงพลังกว่า และ generic constraints
    เป็นเรื่องดีที่ C# ค่อย ๆ นำฟีเจอร์เหล่านี้เข้ามาเช่นกัน แต่ก็น่าเสียดายที่เข้ามาในรูปแบบที่ไม่เข้ากันเอง
    การลงทุนใน F# มีน้อยกว่า C# มาก จึงทำให้ตามหลังในแง่ความเร็วของนวัตกรรมอยู่บ้าง แต่ก็ยังเป็นภาษาที่ยอดเยี่ยม เข้ากันได้กับ ecosystem ของ .NET โดยรวม และให้ประสิทธิภาพระดับเดียวกับ C# ได้ด้วย boilerplate ที่น้อยกว่ามาก

    • ความไม่เข้ากันส่วนใหญ่สรุปได้ว่าเป็นเรื่องของ source generators และเครื่องมืออื่นที่อาศัยการสร้างโค้ด
      สามารถจัดการได้ค่อนข้างง่ายด้วยการเขียนโปรเจ็กต์ C# เสริมเล็ก ๆ ที่มี “โค้ดกาว” ที่จำเป็น
      นอกเหนือจากนั้นก็อยากรู้ว่ามีปัญหาเฉพาะอะไรที่นึกถึงอยู่หรือไม่
      F# 9 ยังรองรับการใช้ ref struct เป็น generic argument ที่เพิ่งเพิ่มเข้ามาใน C# ด้วย และเท่าที่ทราบก็มีแผนจะเพิ่มฟีเจอร์ที่นิยามจากฝั่ง F# เองด้วย
      จนถึงตอนนี้มันทำได้ดีอย่างน่าประทับใจในการไล่ตามให้ทัน และสมควรได้รับการยอมรับมากกว่านี้มาก
  • ข้อความที่ว่า “คลาสที่มีเมธอดเกิน 65,520 เมธอดใน IL ที่ถูกสร้างขึ้น จะเกิดข้อผิดพลาดตอนคอมไพล์แบบใหม่ เพราะ CLR ไม่สามารถโหลดคลาสแบบนั้นได้และจะทำให้เกิดข้อผิดพลาดตอนรันไทม์” นี่ชวนให้จินตนาการแทบไม่ออก
    อย่างไรก็ดี F# เป็นภาษาที่ยอดเยี่ยม
    น่าจะเป็นสิ่งที่ดีที่สุดอันดับสองที่ Microsoft เคยทำออกมารองจาก Excel และทำให้ .NET กลายเป็นแพลตฟอร์มที่สมเหตุสมผล

    • รู้สึกว่า C# ถูกประเมินค่าต่ำเกินไปพอสมควร
      มันสอนได้ค่อนข้างง่ายกับคนที่คุ้นกับ JS หรือ TS อยู่แล้ว และยังเป็นภาษาที่มีผลิตภาพสูง
      มันถูกใช้ในบริบทที่หลากหลายตั้งแต่ game engines, enterprise backends, desktop apps
      ผมคิดว่า Microsoft ทำพลาดไปสองสามครั้งในช่วงแรกจนทำให้การเติบโตช้าลง แต่ในฐานะภาษาทั่วไปมันดีมากจริง ๆ และค่อนข้างเรียนรู้ง่ายด้วย
    • อยากรู้ว่ามองว่าข้อเสียของ F# คืออะไร
      เมื่อหลายปีก่อนเคยลองเล่นผ่าน IDE แบบเบา ๆ ชื่อ LINQPad อยู่พักหนึ่ง แต่หลังจากนั้นก็ไม่ได้ตามต่อว่ามีข้อดีข้อเสียหรือพัฒนาการอะไรบ้าง
      https://www.linqpad.net/
  • ที่ Phosphor เราตัดสินใจครั้งใหญ่ว่าจะฝากอนาคตของบริษัทและทิศทางเทคโนโลยีไว้กับ F# เป็นเวลาหลายปี
    หลังจากลองอยู่กว่าหนึ่งปี เราก็เขียนแอปพลิเคชันใหม่ทั้งหมดด้วย TypeScript และ Rust
    ผลิตภัณฑ์ที่เราสร้างเป็นเครื่องมือสำหรับให้ผู้ใช้ปลายทางเขียนโปรแกรมได้ จึงทำให้เส้นแบ่งแบบดั้งเดิมระหว่างฟรอนต์เอนด์/แบ็กเอนด์ไม่ชัดเจน และ ecosystem ของ .NET ก็ไม่ค่อยเหมาะกับสิ่งนี้
    เดิมทีเราตั้งใจจะใช้ Fable เพื่อคอมไพล์โค้ด F# ไปเป็น JS, Rust, .NET และอื่น ๆ เพื่อรักษา type safety ข้ามหลายเทคโนโลยีและทำ interoperability เท่าที่จำเป็น
    แต่ในทางปฏิบัติ interoperability ระหว่างไลบรารีหลายตัวกลับยากกว่าที่คาดไว้มาก และการจัดการกับ dependency และ binding จำนวนมากรวมถึงการอัปเดตพวกมันก็เจ็บปวดจริง ๆ
    ผมยังคิดว่าสมมติฐานที่ว่า F# ทำให้ได้โค้ดที่สวยงามและมีประสิทธิภาพนั้นยังถูกต้อง แต่ด้วย ecosystem และแนวทางการออกแบบของมัน มันดูเหมาะกับแอปพลิเคชันที่มีเส้นแบ่งฟรอนต์เอนด์/แบ็กเอนด์แบบดั้งเดิมชัดเจนเท่านั้น
    ถ้าเป็นกรณีนั้น ก็คงใช้ F# แค่ฝั่งแบ็กเอนด์
    ตอนนี้เทคโนโลยีที่ตื่นเต้นที่สุดคือ Effect และ Moonbit ที่ใช้อยู่ภายใน
    ไลบรารี Schema ของ Effect ช่วยอุดช่องโหว่หลายจุดใน type system ของ TS และ Moonbit ก็ดูเหมือน F# ยุคใหม่ที่ไม่ต้องพึ่งพา MS/.NET
    Moonbit ถูกออกแบบโดยผู้สร้าง ReScript ซึ่งอาจมองได้ว่าเป็น Fable สำหรับ OCaml และมันออกแบบมาได้ดีมาก พร้อมคอมไพล์ตรงไปเป็น JS, WASM และ native output ที่ปรับแต่งมาอย่างดี
    เราใช้ Effect ใน production แล้ว ส่วน Moonbit ยังไม่ได้ใช้ แต่ในฐานะภาษาที่สร้างมาเพื่อโลกแบบ AI-first มันมีศักยภาพที่น่าทึ่งมาก

    • การคอมไพล์โค้ด F# ออกมาแล้วเปิดให้ใช้เป็น TypeScript modules เป็นประสบการณ์ที่ดี
      เราเขียน business logic หลักและตัวตรวจสอบความถูกต้องด้วย F# แล้วให้แอปฟรอนต์เอนด์ส่วนที่เหลือใช้ TypeScript ส่วนแบ็กเอนด์ใช้ C#
      กล่าวคือเก็บเฉพาะ logic หลักกับ validation ไว้ใน F# แล้วให้ TS กับ C# รับผิดชอบ input/output ทั้งหมด
    • อยากรู้ว่าบริษัทเกี่ยวข้องกับ Darklang หรือเปล่า
      จำได้ว่าเป็นผลิตภัณฑ์คล้ายกันและเขียนด้วย F# แต่ไม่ได้ตามความเคลื่อนไหวล่าสุด
      Effect ค่อนข้างดี และหวังว่าจะมีในภาษาอื่นนอกจาก TypeScript ด้วย
      ส่วน MoonBit ดูเหมือนภาษาโปรแกรมแบบปิดของตัวเอง จึงลังเลที่จะย้ายไปใช้แทนภาษาที่เป็นที่รู้จักมากกว่า เลยอยากรู้ว่าคุณมองประเด็นนั้นอย่างไร
  • ตอนเรียนวิชาเข้ารหัสลับ มีงานที่ให้เลือกใช้ภาษาใดก็ได้ตราบใดที่รันบน .NET และงานชิ้นหนึ่งที่ทำด้วย F# อ่านง่ายกว่าของคนอื่นมาก
    อยากใช้มันให้บ่อยกว่านี้ แต่ตอนนี้งานด้าน data science แทบจะเป็น Python 100%

  • F# 9 ก็ได้รับประโยชน์จากการปรับปรุงประสิทธิภาพเกือบทั้งหมดของ .NET 9 ด้วย
    โดยเฉพาะการปรับปรุงด้าน object escape analysis ที่สำคัญมาก
    https://devblogs.microsoft.com/dotnet/performance-improvemen...

  • คิดถึงช่วงที่ได้ทำงานกับ F# มากจริง ๆ
    มันเป็นภาษาที่มีผลิตภาพสูงจนแค่คอยติดตามอัปเดตก็ยังสนุก
    เมื่อคำนึงถึงขนาดของชุมชนและความไม่ใส่ใจที่บางครั้ง Microsoft แสดงออกมา ผมคิดว่าการรองรับด้านเครื่องมือก็ดีทีเดียว
    สิ่งที่ไม่สะดวกที่สุดคือ ความแม่นยำของ test coverage ของโค้ด

  • ช่วงนี้ได้ลองจับ F# นิดหน่อย และในฐานะคนที่มาจาก Python ก็ชอบมากที่สามารถลองโน่นลองนี่ผ่าน REPL ได้
    เลยสงสัยว่านักพัฒนา F# ที่ชำนาญแล้วก็ใช้งานกันแบบนั้นด้วยไหม
    ฤดูหนาวนี้อยากทำโปรเจ็กต์เว็บแบ็กเอนด์เล็ก ๆ สักตัวเพื่อทำความรู้จักภาษาและอีโคซิสเต็มให้มากขึ้น
    ได้ยินมาว่าฝั่ง HTTP ใช้ Oxpecker แล้วดี แต่อยากรู้ว่ามี PostgreSQL client หรือไดรเวอร์ตัวไหนแนะนำบ้าง
    ไม่ค่อยชอบ ORM
    https://lanayx.github.io/Oxpecker/

    • มีความเป็นไปได้อยู่สองตัว
      https://monazita.gitlab.io/monazita/ เป็นโปรเจ็กต์ที่ทำขึ้นเพื่อโปรเจ็กต์ส่วนตัวระหว่างเรียนรู้ F# ใช้งานพื้นฐานได้ แต่ยังมีพื้นที่ให้ขัดเกลาเพิ่ม และรองรับเฉพาะ PostgreSQL
      https://github.com/jacentino/DbFun ขัดเกลามากกว่าโปรเจ็กต์ก่อนหน้า และรองรับหลายฐานข้อมูล
    • Npgsql เป็นไดรเวอร์ฝั่ง C# ที่ได้รับความนิยม และก็มี F# wrapper ด้วย
      น่าจะเริ่มจากตรงนั้นได้
    • ในฐานะนักพัฒนาที่ใช้หลายภาษา บางครั้งก็มีโอกาสใช้ F# และการพิสูจน์แนวคิดส่วนใหญ่ก็ทำผ่าน REPL
      ถ้ายังไม่แน่ใจเรื่อง API ก็จะกด “Send to F# interactive” เพื่อรันและทดลองจากภายในโมดูลในโค้ดเบสจริงเลย
      ใช้ลองไลบรารีใหม่ ๆ ทำ benchmark แบบเร็ว ๆ หรือใช้แทน PowerShell script ก็ได้
      สามารถทำให้ F# script รันได้ด้วย shebang #!/usr/bin/env -S dotnet fsi ดังนั้นจึงมักใช้เป็นทางเลือกแทน bash/Python สำหรับสคริปต์รอบ ๆ โปรเจ็กต์ .NET ที่ติดตั้ง dotnet-sdk ไว้อยู่แล้ว
      โดยปกติมักรันได้เร็วกว่าและโดยรวมก็กะทัดรัดพอ ๆ กัน
      ความรู้สึกส่วนตัวคือไวยากรณ์และสำนวนของ F# เหมาะกับการเขียนโปรแกรมแบบ REPL ที่เอาโค้ดชิ้นเล็ก ๆ มาต่อกันมากกว่า C#
      ส่วน C# มักต้องมีโครงสร้างเชิงวัตถุมากกว่า
  • สงสัยว่าระบบ การจัดการเวอร์ชัน ของ F# เป็นอย่างไร
    มีการปรับปรุงคุณภาพชีวิตที่ดูดีหลายอย่าง แต่ถ้ามองในมุม semantic versioning ก็ไม่ได้มีการทำลายความเข้ากันได้จนดูสมเหตุสมผลกับการเปลี่ยนเลขเวอร์ชันหลัก และก็ดูไม่ใช่การก้าวกระโดดด้านฟีเจอร์ภาษาขนาดใหญ่พอที่โปรเจ็กต์ซึ่งไม่ได้ใช้ semantic versioning จะขยับจาก 8 ไป 9
    ในคอมเมนต์อื่นมีพูดถึง .NET 9 ที่เพิ่งออกมา เลยสงสัยว่าเป็นการตั้งหมายเลขให้สอดคล้องกับเวอร์ชันของ .NET หรือเปล่า

    • ช่วงหลังมานี้ .NET และ C# ออกรุ่นแบบเพิ่มเลขทีละหนึ่งทุกปี และ F# ก็ดูเหมือนจะใช้แนวทางเดียวกัน
      ไม่แน่ใจว่าเปลี่ยนมาให้ตรงกับจังหวะเวอร์ชันของ .NET โดยตั้งใจ หรือแค่บังเอิญ
      เช่น C# ก็ออก C# 13 ให้ตรงกับ .NET 9
    • ทั้งใน C# และ F# เวอร์ชันของ .NET หมายถึง เวอร์ชันของเครื่องมือ build ที่ใช้ตอนรัน dotnet build
      ซึ่งรวมถึง msbuild, คอมไพเลอร์, แพ็กเกจ NuGet เป็นต้น
      ตัวอย่างเช่น ทีม F# อาจปล่อยการเปลี่ยนแปลงของภาษาออกมาระหว่าง 8 กับ 9 ก็ได้ แต่ถึงไม่ทำแบบนั้น ก็ยังอาจมีการเปลี่ยนแปลงในคอมไพเลอร์หรือ msbuild ที่ต้องใช้ .NET 9 ด้วยเหตุผลบางอย่าง
      โดยทั่วไปนักพัฒนาก็แค่อัปเกรดโค้ดไปใช้ runtime เวอร์ชันล่าสุดได้เลย เว้นแต่จะต้องรอให้ติดตั้ง .NET รุ่นใหม่ในสภาพแวดล้อมที่นำไป deploy ก่อน
      ทุกวันนี้ความจำเป็นนั้นก็น้อยลงแล้วด้วยการเปลี่ยนแปลงใน MSBuild ที่ช่วยให้ทำ self-contained deployment ได้ แต่ก็เป็นเรื่องที่ควรรู้ไว้
    • .NET รุ่นใหม่ออกทุกปี และเวอร์ชันของ C# กับ F# ก็ผูกตามเวอร์ชันประจำปีนั้น
      เพียงแต่ C# นำหน้าอยู่ 4 เวอร์ชัน
      ยังไงก็ตามผมมองว่า semantic versioning ก็ถูกให้ความสำคัญเกินจริงอยู่ดี
  • อยากรู้ว่าสถานะของ F# ในฐานะทางเลือกแทน C# สำหรับทำ แอป GUI บน Windows เป็นอย่างไร
    แล้วมีบริษัทไหนใช้ F# เพื่อจุดประสงค์แบบนี้หรือไม่

  • ไม่เคยลอง F# ด้วยตัวเอง แต่ตอนหาข้อมูลอยู่ แหล่งข้อมูลนี้ดูยอดเยี่ยมมาก: https://fsharpforfunandprofit.com/

    • สำหรับคนที่เพิ่งเริ่มรู้จัก F# นี่เป็นหนึ่งในเว็บไซต์ที่ดีที่สุดจริง ๆ
      ดีทั้งสำหรับนักพัฒนา C# ที่มีประสบการณ์ และคนที่เพิ่งเริ่มเรียนการเขียนโปรแกรมไม่นาน
      ช่วงนี้แทบไม่มีการอัปเดตแล้ว เลยอาจหาเนื้อหาคุยเรื่องฟีเจอร์ใหม่ของ F# 9 ได้ยาก แต่บทความเก่า ๆ นั้นยอดเยี่ยมมากในการทำความเข้าใจแนวคิดอย่าง apply และ bind