19 คะแนน โดย GN⁺ 2024-09-13 | 3 ความคิดเห็น | แชร์ทาง WhatsApp
  • "ไม่ค่อยใช้งานจริง", "เชิงวิชาการ", "เฉพาะกลุ่ม"

    • นี่คือปฏิกิริยาที่ผู้คนมักแสดงออกเมื่อรู้ว่าภาษาโปรแกรมที่ฉันชอบที่สุดคือ Haskell
    • ฉันใช้มันไม่ใช่แค่กับโปรเจ็กต์งานอดิเรก แต่รวมถึงการสร้างเว็บเซิร์ฟเวอร์จริงด้วย
    • ฉันกำลังนำทีมต่าง ๆ ที่ทำงานด้วย Haskell ที่ Converge
  • ความเข้าใจผิดเกี่ยวกับ Haskell

    • ปัญหาที่แก้ได้ด้วยภาษาสำหรับงานทั่วไปนั้น แน่นอนว่าแก้ได้ด้วยภาษาอื่นเช่นกัน
    • ฟีเจอร์จำนวนมากที่ถูกนำเข้าไปใน Python, Rust, Typescript ฯลฯ ได้แรงบันดาลใจจาก Haskell หรือถูกทำไว้ได้แข็งแรงกว่ามาตั้งแต่แรกใน Haskell
    • มันดูเหมือนเป็นรูปแบบหนึ่งของแนวคิด "เลือกเทคโนโลยีที่น่าเบื่อ"
    • มีความเชื่อที่ผิดว่าการเขียนโปรแกรมไม่ใช่คณิตศาสตร์ และควรตัดองค์ประกอบแบบคณิตศาสตร์ออกไป
  • จุดประสงค์ของบทความนี้

    • ต้องการอธิบายอย่างมีเหตุผลว่าทำไม Haskell จึงเป็นตัวเลือกที่ดีที่สุดสำหรับโปรแกรมเมอร์ส่วนใหญ่
    • มีประโยชน์เป็นพิเศษสำหรับผู้ที่ต้องการเขียนซอฟต์แวร์ที่แข็งแรงเชื่อถือได้อย่างมีประสิทธิภาพ
    • และยังเน้นด้านที่สนุกของการเขียนซอฟต์แวร์ด้วย
  • การเลิกนิสัยเดิมและเรียนรู้ใหม่

    • โปรแกรมเมอร์ส่วนใหญ่คุ้นเคยกับพาราไดม์แบบ imperative
    • Haskell เป็นภาษา functional แบบบริสุทธิ์ จึงมีเส้นโค้งการเรียนรู้ที่ชัน
    • แต่ตัวภาษา Haskell เองนั้น ถ้าจำกัดอยู่ใน subset ที่เรียบง่าย ก็เรียนได้ไม่ยาก
    • functional programming ต้องการการเปลี่ยนมุมมองอย่างสิ้นเชิงต่อวิธีประกอบสร้างโปรแกรม
    • กระบวนการนี้ช่วยให้เราเติบโตในฐานะโปรแกรมเมอร์
    • อ้างคำพูดของ Alan Perlis:

      ภาษาใดก็ตามที่ไม่เปลี่ยนวิธีคิดของคุณเกี่ยวกับการเขียนโปรแกรม ก็ไม่คุ้มค่าที่จะเรียนรู้

คำอธิบายไวยากรณ์แบบสั้น ๆ

  • :: ใช้ระบุ type signature (เช่น myThing :: String)

  • การเรียกฟังก์ชันไม่ใช้วงเล็บ แต่เขียนอาร์กิวเมนต์ต่อท้ายชื่อฟังก์ชันโดยคั่นด้วยช่องว่าง (เช่น doSomething withThis withThat)

  • ใน type signature ตัวพิมพ์เล็กหมายถึง type variable ซึ่งแทนชนิดข้อมูลใดก็ได้ (เช่น head :: [a] -> a)

  • มีลูกศรอยู่สองแบบคือ -> และ =>:

    • -> ใช้อธิบายชนิดของฟังก์ชัน (เช่น add1 :: Int -> Int)
    • => ใช้อธิบายข้อจำกัดของ type variable และจะอยู่ก่อนเสมอ (เช่น add1 :: Num a => a -> a)
  • คอมเมนต์เริ่มต้นด้วย --

  • return เป็นฟังก์ชันธรรมดา และไม่ได้มีความหมายแบบที่หลายคนคาดไว้

  • do เป็น syntactic sugar ที่ทำให้โค้ดดูคล้าย imperative

  • มีหลายวิธีในการกำหนดค่าให้ตัวแปรภายในขอบเขตย่อย:

    let x = <something> in  
    <expression>  
    

    หรือ x <- <something>

  • ลดความผิดพลาด

    • ในหลายภาษา เราต้องเขียน test case จำนวนมากเพื่อทำให้โค้ด "ถูกต้อง"
    • Haskell ลดภาระนี้ลงได้มากด้วย type system และ functional programming แบบบริสุทธิ์
    • type system ที่ทรงพลังของ Haskell ให้การรับประกันที่เป็นรูปธรรมเกี่ยวกับโปรแกรม และบังคับใช้อย่างเข้มงวด
    • คุณลักษณะของ type system:
      • ไม่มี nullable type
      • สามารถอธิบายการคำนวณที่อาจล้มเหลวได้
      • มี pattern matching และการตรวจสอบความครบถ้วน
      • หลีกเลี่ยง primitive obsession ได้โดยแทบไม่ต้องออกแรงเพิ่ม
  • ข้อดีของการไม่มีค่า null

    • เมื่อไม่มีค่า null เราจึงรู้ได้เสมอว่าค่านั้นตรงกับชนิดข้อมูลที่คาดไว้
    • ช่วยป้องกัน runtime error และลดพื้นที่ที่อาจเกิดข้อผิดพลาด
  • การแสดงการคำนวณที่อาจล้มเหลว

    • ใช้ชนิดข้อมูล Maybe และ Either เพื่อแสดงอย่างชัดเจนว่าการคำนวณอาจล้มเหลวได้
    • Maybe แทนการคำนวณที่อาจมีผลลัพธ์หรือไม่มีก็ได้
      safeHead :: [a] -> Maybe a  
      
    • Either สามารถมีค่าได้สองแบบ (Left a หรือ Right b)
      validateAddress :: String -> Either AddressParseError ValidAddress  
      
  • Pattern matching และการตรวจสอบความครบถ้วน

    • ต้องจัดการทุกกรณีของโดเมนอินพุต ไม่เช่นนั้นคอมไพเลอร์จะรายงานข้อผิดพลาด
    • สิ่งนี้ช่วยป้องกัน runtime error และเพิ่มความน่าเชื่อถือของโปรแกรม
  • การหลีกเลี่ยง primitive obsession

    • ใช้ newtype เพื่อสร้างชนิดข้อมูลที่มีความหมายเชิงนัยมากขึ้นได้อย่างง่ายดาย
    newtype VenueName = VenueName String  
    newtype EventName = EventName String  
    
  • ข้อดีของ functional programming แบบบริสุทธิ์

    • ข้อมูลไม่เปลี่ยนแปลง จึงไม่ต้องกังวลกับการกลายพันธุ์ของสถานะ
    • side effect ถูกจัดการอย่างชัดเจน และฟังก์ชันพึ่งพาเพียงอินพุตโดยไม่มี side effect แฝง
    • สิ่งนี้ทำให้โปรแกรมคาดเดาได้มากขึ้นและมีเสถียรภาพมากขึ้น
  • การจัดการ side effect อย่างชัดเจน

    • ใช้ IO monad เพื่อแยกและควบคุม side effect ภายในโค้ด
    • เราดูจาก type signature ของฟังก์ชันได้เลยว่ามันก่อ side effect หรือไม่
    sendGreetings :: User -> IO Response  
    
  • Monad และการควบคุม effect

    • ใช้ typeclass และ monad เพื่อเข้ารหัสอย่างแม่นยำว่าฟังก์ชันหนึ่งทำ effect อะไรได้บ้าง
    • ช่วยป้องกัน side effect ที่ไม่ได้ตั้งใจและเพิ่มความเสถียรของโค้ด
  • ปัจจัยที่ช่วยเพิ่มผลิตภาพ

    • ด้วย type system ที่แข็งแรงและคุณสมบัติแบบ pure functional ทำให้ reuse โค้ดและ generalize แนวคิดต่าง ๆ ได้ง่าย
    • ผ่านแนวคิดอย่าง Functor และ Monoid เราสามารถใช้แพตเทิร์นเดียวกันกับโครงสร้างข้อมูลที่หลากหลายได้
    fmap (+2) [1, 2, 3] -- [3, 4, 5]  
    fmap (+2) (Just 2) -- Just 4  
    
  • รีแฟกเตอร์ได้อย่างไร้ความกลัว

    • ความเข้มงวดของคอมไพเลอร์ช่วยลดความเสี่ยงที่จะสร้างบั๊กใหม่เมื่อแก้โค้ด
    • type system ช่วยให้เราแสดงโดเมนของโปรแกรมได้อย่างแม่นยำ จึงแก้ไขโค้ดได้อย่างมั่นใจ
  • เข้าใจโปรแกรมได้ดีขึ้น

    • การเขียนแบบ declarative ทำให้แสดงโดเมนของปัญหาได้อย่างตรงไปตรงมา
    • ช่วยให้เข้าใจความหมายของโปรแกรมได้ง่ายและเพิ่มความน่าเชื่อถือ
    • การตัดความซับซ้อนที่ไม่จำเป็นออกไปทำให้สามารถให้เหตุผลกับโปรแกรมได้อย่างสมเหตุสมผล
  • Algebraic data type และ typeclass

    • สามารถสร้าง domain-specific language ภายใน Haskell ได้
    • สิ่งนี้ช่วยให้เข้าใจและบำรุงรักษาโปรแกรมได้ง่ายขึ้น
  • ตัวอย่างโปรแกรม

    • เขียนเครื่องมือบัญชีอย่างง่ายเพื่อประยุกต์ใช้แนวคิดของ Haskell ในทางปฏิบัติ

บทส่งท้าย

  • การใช้ Haskell ทั้งสนุกและมีประสิทธิผล
  • การผสานกันของ type system ที่ทรงพลังและสื่อความหมายได้ดี กับ functional programming แบบบริสุทธิ์ คือสิ่งที่ทำให้ Haskell โดดเด่น
  • แม้ว่าภาษาอื่น ๆ จะเริ่มนำความสามารถเหล่านี้มาใช้ แต่ใน Haskell คุณลักษณะเหล่านี้เป็นส่วนหนึ่งของแก่นของภาษา
  • การเรียนรู้ Haskell จะเปลี่ยนวิธีคิดของคุณต่อการเขียนโปรแกรม

ความเห็นของ GN⁺

  • คุณค่าของการเรียนรู้ Haskell

    • ช่วยขยายกรอบความคิดในฐานะโปรแกรมเมอร์
    • หากเข้าใจพาราไดม์ functional programming ก็จะเขียนโค้ดในภาษาอื่นได้ดีขึ้นด้วย
  • การเติบโตของ functional programming

    • มีจุดแข็งด้าน parallel processing และ concurrency จึงเหมาะกับสภาพแวดล้อมการคำนวณสมัยใหม่
    • การควบคุม side effect ช่วยให้เขียนโค้ดที่คาดเดาได้
  • การเปรียบเทียบกับภาษาอื่น

    • แม้จะมีภาษาอย่าง Rust หรือ Scala ที่รองรับ functional programming แต่ความบริสุทธิ์และ type system ของ Haskell ยังโดดเด่นเป็นพิเศษ
    • แนวคิดของ Haskell ยังมีประโยชน์เมื่อเรียนรู้ภาษาใหม่อื่น ๆ
  • ความเป็นไปได้ในการใช้งานจริง

    • แม้ช่วงเริ่มต้นจะมีเส้นโค้งการเรียนรู้ที่ชัน แต่เวลาที่ลงทุนไปจะให้ผลตอบแทนด้านผลิตภาพ
    • มีประโยชน์ในระบบที่ซับซ้อนหรือโดเมนที่ไวต่อความผิดพลาด
  • ชุมชนและ ecosystem

    • ชุมชน Haskell มีความเคลื่อนไหวสูง และมีการพัฒนาไลบรารีกับเครื่องมือต่าง ๆ อย่างต่อเนื่อง
    • สามารถพัฒนาทักษะได้ผ่านการมีส่วนร่วมในโปรเจ็กต์โอเพนซอร์ส

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

 
cosine20 2024-09-19

ผมเริ่มต้นกับ F# ซึ่งเพิ่มความใช้งานได้จริงเข้าไป

 
savvykang 2024-09-13

ADT กับ pattern matching นั้นดีอยู่หรอก แต่ช่วยอย่าพูดถึง monad กับ functor มากนักได้ไหม

 
GN⁺ 2024-09-13
ความเห็นจาก Hacker News
  • Haskell บังคับให้เขียน total function แทน partial function

    • Haskell ไม่ได้ป้องกันการเรียกซ้ำแบบไม่สิ้นสุด
    • ใน ecosystem ของ FP ที่กำลังขยับไปสู่ dependent types การทำให้ type checker ไม่รันไม่รู้จบเป็นเรื่องสำคัญ
    • ส่วนขยายเฉพาะกิจจำนวนมากของ Haskell ก่อปัญหา
    • ถ้าชอบปรัชญาของ Haskell ก็ไม่ควรจำกัดตัวเองไว้แค่ Haskell
    • การทำมาตรฐานของ Haskell ล้มเหลว
    • คุณค่าเฉพาะของ GHC อาจเป็น runtime system ของ GHC
  • ใช้ Haskell มา 10 ปีแล้ว และเครื่องมือก็ดีขึ้นมาก

    • ghcup, cabal sandboxing และ HLS มีความเสถียร
    • แทบไม่ค่อยพบจุดขาดตกบกพร่องใน ecosystem ของไลบรารี
    • เวลา compile ของ Haskell ยังน่าหงุดหงิดอยู่
    • เวลา compile dependency ยาวนาน
  • type system ของ Haskell ไม่ได้พิสูจน์ว่าฟังก์ชันเป็น total

    • ในการเขียนโปรแกรมทั่วไป การพิสูจน์ totality ไม่ได้มีประโยชน์มากนัก
    • คนส่วนใหญ่มักตรวจสอบว่าโปรแกรมทำงานจริงหรือไม่ด้วยการทดสอบ
  • ภาษาของ Haskell ดี แต่ ecosystem ยังต้องไปต่ออีกไกล

    • compiler ช้า
    • ความสามารถในการรายงานข้อผิดพลาดยังไม่ดี
    • ข้อผิดพลาดแรกทำให้การ compile ที่เหลือหยุดทั้งหมด
    • เครื่องมือยังด้อยกว่าเมื่อเทียบกับภาษา functional อื่น ๆ
    • ecosystem ของไลบรารียังไม่เพียงพอ
    • แนวคิดของ Haskell มีอิทธิพลต่อภาษาอื่นอีกมากมาย
  • อยากใช้ Haskell หรือภาษา functional อื่น ๆ ในงานอาชีพ

    • ภาษาอย่าง Go เรียนรู้ได้ง่าย
    • อยากเรียนรู้วิธีสร้าง codebase ในภาษา functional
  • Haskell มีอิทธิพลอย่างมากต่อวิธีคิดเรื่องการเขียนโปรแกรมและสถาปัตยกรรมของโค้ด

    • type system ของ Haskell ทรงพลังมากและเข้าใจได้ง่าย
    • การทำ micro-optimize โค้ด Haskell เป็นเรื่องสนุก
    • เครื่องมือยังคงขาดอยู่
  • Haskell ทดลองใช้ laziness ในระดับภาษา

    • laziness สามารถได้มาที่ระดับ standard library
  • ความสุดโต่งของ Haskell ในเรื่องความบริสุทธิ์และ immutability เป็นปัญหา

    • โปรแกรมเมอร์จำนวนมากมองว่าลูปแบบ procedural/เปลี่ยนแปลงค่าได้แสดงออกได้ง่ายกว่า
    • Rust ใช้ type system ที่มีความสามารถและมีสำนวนแบบ functional มากมาย แต่ก็ยังใช้ลูปและ mutability ได้
  • Haskell เหมาะมากกับซอฟต์แวร์ business logic (BLOBS)

    • สามารถจำลอง business logic ส่วนใหญ่ได้ด้วย type ที่เรียบง่ายและ pattern matching
    • ถ้ารักษาส่วนที่เรียบง่ายไว้ ก็สอนให้ผู้ร่วมพัฒนาที่ไม่ใช่สายเทคนิคได้ง่าย
    • Haskell สนุก