1 คะแนน โดย GN⁺ 27 일 전 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • มีการเสนอ แบ็กเอนด์ใหม่ที่รองรับการสร้างโค้ด C++ ให้กับคอมไพเลอร์ OCaml เพื่อชดเชยข้อจำกัดของแบ็กเอนด์ C แบบเดิม
  • โค้ดที่แปลงแล้วจะเขียนในรูปแบบ ฟังก์ชันล้วน และมีการนำบางส่วนของโมดูล List มาเขียนใหม่ โดยไม่ใช้สถานะแบบเปลี่ยนแปลงได้หรือไลบรารีมาตรฐาน
  • การรันต้องใช้ คอมไพเลอร์ C++ (g++) และรองรับออปชันสำหรับปลดข้อจำกัดความลึกของเทมเพลตหรือส่งอาร์กิวเมนต์
  • ประสิทธิภาพแตกต่างกันไปตามคอมไพเลอร์ และเมื่อใช้ อัลกอริทึม sieve แบบอิง priority queue ที่ปรับปรุงแล้ว จะช่วยเพิ่มความเร็วและประสิทธิภาพด้านหน่วยความจำ
  • ชุมชนมองว่านี่คือ การทดลองผสานภาษาเชิงฟังก์ชันกับเทมเพลตเมตาโปรแกรมมิง และยังมีการพูดถึงความเป็นไปได้ในการขยายไปยัง Rust

ข้อเสนอเพิ่มแบ็กเอนด์ C++

  • มีการเสนอแพตช์เพื่อ เพิ่มแบ็กเอนด์ C++ ให้กับคอมไพเลอร์ OCaml (ocamlc)
    • เป็นรูปแบบที่ปรับปรุงจากแบ็กเอนด์ C แบบไม่เป็น incremental ซึ่งใช้อยู่ในรันไทม์และ FFI เดิม
    • สามารถแปลงโค้ด OCaml เป็น C++ ได้ด้วยคำสั่ง ocamlc -incr-c primes.ml
  • โค้ด C++ ที่แปลงแล้วจะเขียนในรูปแบบ ฟังก์ชันล้วน และไม่รองรับสถานะแบบเปลี่ยนแปลงได้
    • ด้วยเหตุนี้จึง ไม่สามารถใช้ไลบรารีมาตรฐานได้ และในตัวอย่างมีการเขียนบางส่วนของโมดูล List ขึ้นใหม่ในสไตล์ฟังก์ชันล้วน
    • เอาต์พุตจะแสดงในรูปโครงสร้างซ้อนแบบ Cons<hd, tl> และใช้โครงสร้างแยกเพื่อหลีกเลี่ยงการชนกับตัวดำเนินการ :: ของ C++
  • การรันต้องใช้ คอมไพเลอร์ C++ (g++) และสามารถส่งอาร์กิวเมนต์ได้ด้วยออปชัน -Dlimit=100
    • ผลลัพธ์การรันจะแสดงในรูปแบบข้อความผิดพลาดของคอมไพเลอร์
    • หากเป็นการคำนวณขนาดใหญ่ สามารถปลดข้อจำกัดความลึกของเทมเพลตได้ด้วยออปชัน -ftemplate-depth=999999
  • ประสิทธิภาพแตกต่างกันไปตามคอมไพเลอร์
    • g++ ใช้เวลาประมาณ 30 วินาทีและหน่วยความจำ 11GiB สำหรับการคำนวณจำนวนเฉพาะไม่เกิน 10000
    • clang++ เตือนภายในไม่ถึง 1 วินาทีก่อนเกิด segmentation fault
    • เมื่อใช้งาน อัลกอริทึม sieve ของ O’Neill ที่อิง priority queue ประสิทธิภาพดีขึ้นเป็น 8 วินาทีและใช้หน่วยความจำ 3.1GiB
  • มีการกล่าวถึง ทิศทางการขยายในอนาคต ว่าอาจรองรับ Rust ได้
    • มีการระบุว่าหาก Rust ทำ impl specialization แบบบางส่วนได้สมบูรณ์ ก็อาจสามารถรันโปรแกรม OCaml ได้

ปฏิกิริยาและการถกเถียงของชุมชน

  • การทดสอบฟีเจอร์และฟีดแบ็ก

    • redianthus ถามว่ารองรับ ชนิดข้อมูลเวียนเกิดแบบไม่เป็นเอกพันธ์ หรือไม่
    • stedolan แก้ข้อผิดพลาดที่เกิดจาก %predint ยังไม่ได้ถูก implement และยืนยันว่าชนิดข้อมูลดังกล่าวทำงานได้ตามปกติ
  • มุกตลกและปฏิกิริยา

    • avsm แซวว่า “อยากได้ C-- แต่ดันเป็น C++ งั้นประนีประนอมด้วย C# แล้วกัน”
    • stedolan ตอบกลับว่า “ปีหน้าจะลองกับจำนวนเชิงซ้อน ℂ”
    • มีปฏิกิริยาด้วยอีโมจิอย่าง 😂, ❤️, 🚀 จำนวนมาก สะท้อนการตอบรับเชิงบวกจากชุมชน
  • ข้อเสนอเชิงเทคนิค

    • AdelKS เสนอทางเลือกโดยใช้ การประเมินผลแบบ constexpr แทนเทมเพลต
      • พร้อมแชร์โค้ดตัวอย่างที่คำนวณจำนวนเฉพาะตอนคอมไพล์และใส่ผลลัพธ์ลงในไบนารีโดยตรง
    • LoganDark ตอบแบบขำ ๆ ว่า “แบบนั้นมันไม่ใช่ความสนุกแท้ ๆ” เพื่ออธิบายเหตุผลที่ใช้เทมเพลต
  • การอภิปรายเพิ่มเติม

    • redianthus กล่าวว่า “ตอนนี้ C++ กลายเป็นภาษาเชิงฟังก์ชันอย่างแท้จริงแล้ว”
      • พร้อมเน้นว่าสามารถนำโครงสร้างข้อมูลแบบฟังก์ชันล้วนของ OCaml ไปทำใน C++ ได้
    • dzmitry-lahoda กล่าวถึงโปรเจกต์ที่ทำให้รัน OCaml บน Rust ได้แล้ว (contextgeneric/cgp)

ตัวอย่างประสิทธิภาพและการรัน

  • ตัวอย่างพื้นฐาน: โปรแกรมคำนวณจำนวนเฉพาะ
    • ocamlc -incr-c primes.ml → สร้าง primes.cpp
    • รัน g++ -Dlimit=100 primes.cpp แล้วจะแสดงรายการจำนวนเฉพาะ
  • การตั้งค่าเพื่อประสิทธิภาพสูง

    • g++ -ftemplate-depth=999999 -Dlimit=10000 primes.cpp
    • ใช้เวลาประมาณ 30 วินาที และหน่วยความจำ 11GiB
  • เมื่อใช้อัลกอริทึมที่ปรับปรุงแล้ว

    • ประสิทธิภาพดีขึ้นเป็น 8 วินาที และใช้หน่วยความจำ 3.1GiB

บทสรุป

  • PR นี้คือ การทดลองแบ็กเอนด์แบบใหม่ที่แปลง OCaml เป็น C++ ซึ่งแสดงให้เห็นความเป็นไปได้ของการผสานภาษาเชิงฟังก์ชันเข้ากับเทมเพลตเมตาโปรแกรมมิง
  • ชุมชนมองว่านี่เป็น กรณีตัวอย่างของการผสานมุกเชิงเทคนิคกับการทดลองอย่างสร้างสรรค์ และมีการตอบรับอย่างคึกคัก
  • ยังมีการชี้ถึงความเป็นไปได้ในการขยายไปยังภาษาอื่นอย่าง Rust ด้วย

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

 
GN⁺ 27 일 전
ความคิดเห็นจาก Hacker News
  • เนื้อหายอดเยี่ยมมาก อยากให้ทิปอย่างหนึ่งเวลาต้องเขียน โค้ด C++ ที่รันนาน ๆ
    น่าแปลกที่ C++ interpreter ไม่มี tail call optimization เลย
    เพราะงั้นโค้ด C++ แบบที่เป็นสำนวนส่วนใหญ่จึงมักเขียนฟังก์ชันอย่าง reverse, map, range, filter ขึ้นมาเองเพื่อไม่ให้สแตกพัง
    ถ้าเขียนแบบนี้ คนที่ต้องมาดูแลต่อจะสบายกว่ามาก อย่าไปพึ่ง command-line flag เลย ใช้ แนวทางที่พกพาได้ จะดีกว่า

  • พออ่านประโยคที่ว่า “ถ้าใช้โครงสร้างข้อมูลระดับสูงแบบนี้ g++ จะคำนวณจำนวนเฉพาะที่น้อยกว่า 10000 ได้ในเวลาแค่ 8 วินาที และใช้หน่วยความจำเพียง 3.1GiB” ก็หลุดขำออกมา
    ในที่สุดก็ คำนวณจำนวนเฉพาะบนโน้ตบุ๊ก ของฉันได้แล้ว

  • เห็นตรงที่บอกว่า “โค้ดนี้ถูกแปลเป็น C++ ที่ idiomatic และอ่านง่าย” แล้วรู้สึกเห็นด้วยมาก
    ในฐานะคนที่ชอบ C++ ฉันคิดว่านี่คือ โค้ด C++ ที่อ่านง่าย จริง ๆ

    • ส่วนใหญ่ก็เห็นด้วย แต่ตรง typedef I<((I<((n::val (p::val))>::val) != (I<0>::val))> res; นี่มัน ลูกเล่นเทมเพลตระดับเวทมนตร์ ชัด ๆ
      นี่เป็นครั้งแรกที่ฉันเห็นการใส่นิพจน์เงื่อนไขไว้ใน type definition ของ C++
      พอมาดูทีหลังถึงรู้ว่านี่ไม่ใช่โค้ดจริง แต่เป็นส่วนหนึ่งของตรรกะการประเมินเทมเพลต
      พูดอีกอย่างคือ มีการ โยนบางส่วนของตรรกะคอมไพเลอร์ของภาษาระดับสูงไปให้ template engine จัดการ
      วิธีแบบนี้อาจมีประสิทธิภาพกว่าการไปเสียเวลากับ parser เพิ่มก็ได้
      เลยทำให้ตอนนี้ฉันเริ่มคิดว่าอาจลองใช้ C++ เป็นเป้าหมายการ lowering ของ elevate compiler framework ที่กำลังพัฒนาอยู่
  • ตอนเห็นประโยค “C++ is a purely functional language” ตอนแรกฉันนึกว่าเป็นพิมพ์ผิดจนต้องเลิกคิ้ว
    แต่พอรู้ว่าไม่ได้พิมพ์ผิดก็ยิ่งน่าสนใจเข้าไปอีก เนื้อหาที่เหลือก็ดีเยี่ยมด้วย

  • บทความนี้ทำให้ทั้งวันของฉันสดใสขึ้นเลย ขอบคุณ

  • Stephen Dolan ไม่เคยทำให้ผิดหวังเลย สร้างความประหลาดใจได้ทุกครั้ง

  • ตอนอ่านตรงที่ว่า “C++ เป็นภาษาฟังก์ชันบริสุทธิ์ และไม่รองรับ mutable state การจะรันโปรแกรม C++ ต้องใช้ C++ interpreter”
    แวบแรกฉันนึกว่าเป็น มุกวันโกหกเดือนเมษายน เสียอีก ทั้งที่เมษายนก็ผ่านไปแล้ว