ฟีเจอร์ใหม่ใน F# 9
(learn.microsoft.com)- 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
- F# ถูกออกแบบมาให้หลีกเลี่ยง
-
พร็อพเพอร์ตี
.Is*ของ discriminated union- discriminated union มี พร็อพเพอร์ตี
.Is*ที่สร้างให้อัตโนมัติสำหรับแต่ละเคส - ตัวอย่างเช่น หากชนิด
ContactมีเคสEmailและPhoneสามารถตรวจสอบว่าเป็นเคสใดเคสหนึ่งได้ด้วยperson.contact.IsEmail - เดิมทีต้องเขียนโค้ดแบบ
Email _ -> true | _ -> falseด้วยนิพจน์matchเพื่อทำการตรวจสอบเดียวกัน
- discriminated union มี พร็อพเพอร์ตี
-
partial active pattern ที่คืนค่า
bool- partial active pattern เดิมต้องคืนค่า
Some ()เมื่อ match สำเร็จ และNoneเมื่อไม่สำเร็จ - ใน F# 9 อนุญาตให้ คืนค่า
boolได้ด้วย - ในตัวอย่างการ match สตริงแบบไม่สนตัวพิมพ์เล็กใหญ่ สามารถคืนค่าผลลัพธ์ของ
String.Equals(..., StringComparison.OrdinalIgnoreCase)ได้โดยตรง
- partial active pattern เดิมต้องคืนค่า
-
ให้ความสำคัญกับ 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
- directive
-
อนุญาต 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 เหล่านี้ไม่ส่งผลต่อการทำงานของโค้ด แต่อาจทำให้ผู้อ่านสับสนได้
- F# 9 จะแจ้งเตือนเมื่อ 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 พึ่งพาพฤติกรรมเดิมอยู่หรือไม่
- F# มีลักษณะที่บันทึก private member ใน IL เป็น internal ทำให้โปรเจกต์ที่ไม่ใช่ F# ซึ่งเข้าถึงโปรเจกต์ F# ได้ผ่าน
การเปลี่ยนแปลงในไลบรารีมาตรฐาน FSharp.Core
-
ฟังก์ชันสุ่มสำหรับคอลเลกชัน
- เพิ่มฟังก์ชัน สุ่มตัวอย่างและสับลำดับ ในโมดูล
List,Array,Seq - ทำให้ใช้งาน F# ได้ง่ายขึ้นในสถานการณ์ทั่วไปที่ต้องการความสุ่ม เช่น data science, machine learning, การพัฒนาเกม
- ทุกฟังก์ชันมีสามรูปแบบ
- รูปแบบที่ใช้ instance
Randomที่แชร์ร่วมกันแบบ implicit และ thread-safe - รูปแบบที่รับ instance
Randomเป็นอาร์กิวเมนต์ - รูปแบบที่รับฟังก์ชัน
randomizerแบบกำหนดเอง ซึ่งต้องคืนค่าfloatตั้งแต่ 0.0 ขึ้นไปและน้อยกว่า 1.0
- รูปแบบที่ใช้ instance
- ฟังก์ชันที่มีให้คือ
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")>]ได้
- เพิ่ม constructor แบบไม่มีอาร์กิวเมนต์ให้
-
รองรับ 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 แล้วสำหรับกรณีของนิพจน์
-
การ 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 ความคิดเห็น
ความคิดเห็นจาก Hacker News
F# เป็นภาษาที่ชอบที่สุดมาตลอดนับตั้งแต่ได้รู้จักครั้งแรกในมหาวิทยาลัย
มันล้ำหน้า C# ไปมากในด้านฟีเจอร์อย่าง discriminated unions, null safety, pattern matching, records, การอนุมานชนิดข้อมูลที่ทรงพลังกว่า และ generic constraints
เป็นเรื่องดีที่ C# ค่อย ๆ นำฟีเจอร์เหล่านี้เข้ามาเช่นกัน แต่ก็น่าเสียดายที่เข้ามาในรูปแบบที่ไม่เข้ากันเอง
การลงทุนใน F# มีน้อยกว่า C# มาก จึงทำให้ตามหลังในแง่ความเร็วของนวัตกรรมอยู่บ้าง แต่ก็ยังเป็นภาษาที่ยอดเยี่ยม เข้ากันได้กับ ecosystem ของ .NET โดยรวม และให้ประสิทธิภาพระดับเดียวกับ C# ได้ด้วย boilerplate ที่น้อยกว่ามาก
สามารถจัดการได้ค่อนข้างง่ายด้วยการเขียนโปรเจ็กต์ C# เสริมเล็ก ๆ ที่มี “โค้ดกาว” ที่จำเป็น
นอกเหนือจากนั้นก็อยากรู้ว่ามีปัญหาเฉพาะอะไรที่นึกถึงอยู่หรือไม่
F# 9 ยังรองรับการใช้
ref structเป็น generic argument ที่เพิ่งเพิ่มเข้ามาใน C# ด้วย และเท่าที่ทราบก็มีแผนจะเพิ่มฟีเจอร์ที่นิยามจากฝั่ง F# เองด้วยจนถึงตอนนี้มันทำได้ดีอย่างน่าประทับใจในการไล่ตามให้ทัน และสมควรได้รับการยอมรับมากกว่านี้มาก
ข้อความที่ว่า “คลาสที่มีเมธอดเกิน 65,520 เมธอดใน IL ที่ถูกสร้างขึ้น จะเกิดข้อผิดพลาดตอนคอมไพล์แบบใหม่ เพราะ CLR ไม่สามารถโหลดคลาสแบบนั้นได้และจะทำให้เกิดข้อผิดพลาดตอนรันไทม์” นี่ชวนให้จินตนาการแทบไม่ออก
อย่างไรก็ดี F# เป็นภาษาที่ยอดเยี่ยม
น่าจะเป็นสิ่งที่ดีที่สุดอันดับสองที่ Microsoft เคยทำออกมารองจาก Excel และทำให้ .NET กลายเป็นแพลตฟอร์มที่สมเหตุสมผล
มันสอนได้ค่อนข้างง่ายกับคนที่คุ้นกับ JS หรือ TS อยู่แล้ว และยังเป็นภาษาที่มีผลิตภาพสูง
มันถูกใช้ในบริบทที่หลากหลายตั้งแต่ game engines, enterprise backends, desktop apps
ผมคิดว่า Microsoft ทำพลาดไปสองสามครั้งในช่วงแรกจนทำให้การเติบโตช้าลง แต่ในฐานะภาษาทั่วไปมันดีมากจริง ๆ และค่อนข้างเรียนรู้ง่ายด้วย
เมื่อหลายปีก่อนเคยลองเล่นผ่าน 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 มันมีศักยภาพที่น่าทึ่งมาก
เราเขียน business logic หลักและตัวตรวจสอบความถูกต้องด้วย F# แล้วให้แอปฟรอนต์เอนด์ส่วนที่เหลือใช้ TypeScript ส่วนแบ็กเอนด์ใช้ C#
กล่าวคือเก็บเฉพาะ logic หลักกับ validation ไว้ใน F# แล้วให้ TS กับ C# รับผิดชอบ input/output ทั้งหมด
จำได้ว่าเป็นผลิตภัณฑ์คล้ายกันและเขียนด้วย 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 ขัดเกลามากกว่าโปรเจ็กต์ก่อนหน้า และรองรับหลายฐานข้อมูล
น่าจะเริ่มจากตรงนั้นได้
ถ้ายังไม่แน่ใจเรื่อง 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# ก็ออก C# 13 ให้ตรงกับ .NET 9
dotnet buildซึ่งรวมถึง msbuild, คอมไพเลอร์, แพ็กเกจ NuGet เป็นต้น
ตัวอย่างเช่น ทีม F# อาจปล่อยการเปลี่ยนแปลงของภาษาออกมาระหว่าง 8 กับ 9 ก็ได้ แต่ถึงไม่ทำแบบนั้น ก็ยังอาจมีการเปลี่ยนแปลงในคอมไพเลอร์หรือ msbuild ที่ต้องใช้ .NET 9 ด้วยเหตุผลบางอย่าง
โดยทั่วไปนักพัฒนาก็แค่อัปเกรดโค้ดไปใช้ runtime เวอร์ชันล่าสุดได้เลย เว้นแต่จะต้องรอให้ติดตั้ง .NET รุ่นใหม่ในสภาพแวดล้อมที่นำไป deploy ก่อน
ทุกวันนี้ความจำเป็นนั้นก็น้อยลงแล้วด้วยการเปลี่ยนแปลงใน MSBuild ที่ช่วยให้ทำ self-contained deployment ได้ แต่ก็เป็นเรื่องที่ควรรู้ไว้
เพียงแต่ C# นำหน้าอยู่ 4 เวอร์ชัน
ยังไงก็ตามผมมองว่า semantic versioning ก็ถูกให้ความสำคัญเกินจริงอยู่ดี
อยากรู้ว่าสถานะของ F# ในฐานะทางเลือกแทน C# สำหรับทำ แอป GUI บน Windows เป็นอย่างไร
แล้วมีบริษัทไหนใช้ F# เพื่อจุดประสงค์แบบนี้หรือไม่
https://github.com/fsprojects/Avalonia.FuncUI
https://fabulous.dev/ รองรับ Avalonia/MAUI/Xamarin
https://github.com/kekyo/epoxy รองรับ Avalonia และ WPF
ถ้าอยากรู้ว่ามีบริษัทใช้ในลักษณะนี้ไหม อาจลองถามคนรอบตัวดูได้
ไม่เคยลอง F# ด้วยตัวเอง แต่ตอนหาข้อมูลอยู่ แหล่งข้อมูลนี้ดูยอดเยี่ยมมาก: https://fsharpforfunandprofit.com/
ดีทั้งสำหรับนักพัฒนา C# ที่มีประสบการณ์ และคนที่เพิ่งเริ่มเรียนการเขียนโปรแกรมไม่นาน
ช่วงนี้แทบไม่มีการอัปเดตแล้ว เลยอาจหาเนื้อหาคุยเรื่องฟีเจอร์ใหม่ของ F# 9 ได้ยาก แต่บทความเก่า ๆ นั้นยอดเยี่ยมมากในการทำความเข้าใจแนวคิดอย่าง
applyและbind