เหตุผลที่ผมเลือก Common Lisp
(blog.djhaskin.com)ลาก่อน, Clojure
- ใช้ Clojure มาประมาณ 7 ปี แต่ไม่พอใจกับปัญหา "การเริ่มทำงานช้า" ของแอป CLI อีกต่อไป
- แม้จะมีโปรเจกต์อย่าง babashka แต่ก็แก้ปัญหาการเริ่มทำงานช้าได้ยาก แม้จะใช้ GraalVM
native-imageก็ตาม - "การเริ่มทำงานที่รวดเร็วของไฟล์ปฏิบัติการแบบสแตนด์อโลน" กลายเป็นข้อกำหนดที่จำเป็น และตัดสินว่า Clojure ไม่ตอบโจทย์นี้
มองหา Lisp ตัวใหม่
- สำรวจหลายภาษาเพื่อหา Lisp ตัวใหม่ โดยมองหาภาษาที่แก้ปัญหาที่เคยเจอในโปรเจกต์เดิมได้
- แม้จะไม่ได้มี "ข้อกำหนดที่ชัดเจน" ตั้งแต่แรก แต่สุดท้ายก็สรุปเกณฑ์ได้ดังนี้
- ต้องสามารถสร้าง "ไฟล์ปฏิบัติการที่รันได้เองและเริ่มทำงานเร็ว" ได้ด้วย toolchain ที่สมเหตุสมผล (เพื่อแก้ข้อไม่พอใจหลักใน Clojure)
- เนื่องจากใช้ Emacs ไม่ได้ จึงต้องใช้งานบน Vim ได้
- ต้องรองรับ Windows และ Mac จะรองรับแค่ Linux/POSIX ไม่ได้
- ถ้าสามารถทำปลั๊กอินหรือเชื่อมต่อกับภาษาคอมมูนิตี้ใหญ่ภาษาอื่นได้แบบ Clojure กับ Java ก็จะดี
- ความเร็วขณะรันต้องเร็วพอ (อย่างน้อยระดับ Clojure หรือดีกว่า)
- ต้องรองรับมัลติเธรดได้ดี และถ้าเป็นไปได้ไม่ควรมีอะไรแบบ GIL (Global Interpreter Lock)
- ต้องมีคอมมูนิตี้ที่แข็งแรง
- ต้องมี ecosystem ที่เพียงพอ อย่างน้อยควรมีไลบรารีต่อไปนี้
- การ parse และ serialize JSON
- รองรับ Sqlite3
- ไลบรารีสำหรับ HTTP request
- รองรับโครงสร้างข้อมูลเชิงฟังก์ชันแบบเดียวกับ Clojure (แต่ข้อนี้สำคัญน้อยกว่า)
- ภาษาที่ลองพิจารณา
- Scheme : มาตรฐาน r6rs และ r7rs ทำให้คอมมูนิตี้แตกออกเป็นหลายฝั่ง จึงไม่ค่อยดึงดูดใจ และ ecosystem ก็เล็กเกินไปสำหรับความต้องการ
- Racket : เคยใช้สมัยเรียน แต่รู้สึกว่า runtime ช้าและตัวระบบค่อนข้างหนัก จึงไม่ชอบ
- Common Lisp : พบจาก lisp-lang.org คอมมูนิตี้และข้อมูลประกอบน่าประทับใจ จึงตัดสินใจลอง
Magic Happens Here
- ขอละรายละเอียดการเดินทางทั้งหมดในการเรียนรู้ Common Lisp แต่กระบวนการเรียนรู้นั้นค่อนข้างหนักเอาเรื่อง
- จุดเริ่มต้นไม่ค่อยดีนัก ตอนคริสต์มาสได้หนังสือ CLtLv2 มาและเริ่มจากการอ่านเล่มนั้น
- ต่อมาจึงพบ HyperSpec และเริ่มอ่าน ทำให้การเรียนรู้ไปในทิศทางที่ดีกว่าเดิม
- Common Lisp มีลักษณะเฉพาะบางอย่าง
- เป็นภาษาที่มีการทำมาตรฐานไว้ คล้าย C มากกว่า Java
- มีทั้งคอมไพเลอร์ อินเทอร์พรีเตอร์ และรันไทม์หลายตัวที่ implement มาตรฐานนี้
- มีเครื่องมืออย่าง Roswell สำหรับติดตั้งและจัดการ implementation หลายแบบ
- implementation ที่ได้รับความนิยมมากที่สุดในคอมมูนิตี้ดูจะเป็น SBCL
- ถ้าตอนเริ่มสำรวจได้รู้จัก Janet ตั้งแต่แรกจะเป็นอย่างไร
- Janet มีคุณสมบัติดังต่อไปนี้ จึงอาจทำให้พอใจก่อนจะไปเรียน Common Lisp
- syntax กระชับ, ไฟล์ปฏิบัติการเล็กและเร็ว, รองรับ C FFI
- มีคู่มือเริ่มต้นที่สนุก
- ตอบโจทย์ทุกข้อที่ผู้เขียนให้ความสำคัญเป็นการส่วนตัว
- แต่เหตุผลที่เลือก Common Lisp
- ไม่อย่างนั้นคงพลาดฟีเจอร์ระดับสูงอย่าง CLOS และ Condition System ที่มาเจอทีหลัง
- Common Lisp เป็นภาษาที่ทรงพลังกว่า
ข้อกำหนดที่ตอบโจทย์แล้ว
หลังจากยืนยันได้ว่า Common Lisp ตอบโจทย์ตามข้อกำหนด ผู้เขียนก็เลือกมันเป็นภาษา Lisp ถัดไปและใช้งานมาจนถึงตอนนี้ สิ่งที่ค้นพบหลัก ๆ มีดังนี้:
- ไฟล์ปฏิบัติการแบบสแตนด์อโลน:
- Common Lisp มีหลายวิธีในการสร้างไฟล์ปฏิบัติการแบบสแตนด์อโลน
- เวลาเริ่มทำงานของไฟล์ปฏิบัติการ ตั้งแต่เร็วเพียงเศษเสี้ยววินาทีไปจนถึงแทบจะทันที ขึ้นอยู่กับว่าจะบีบอัดหรือไม่
- ความสามารถนี้ไม่ได้เป็นแค่ตัวเลือกเสริม แต่ถูกออกแบบให้เป็นวิธีหลักในการแจกจ่ายโปรแกรม Lisp
- เวิร์กโฟลว์บน Vim:
- มีตัวเลือกดี ๆ อยู่หลายแบบ แต่โดยส่วนตัวแล้วผู้เขียนจัดเวิร์กโฟลว์บน Vim ขึ้นมาใช้เอง
- และยังพบว่า VS Code ก็ใช้งานเป็น IDE สำหรับ Common Lisp ได้ดีพอสมควร
- การรองรับ Windows/Mac/Linux:
- SBCL รองรับระบบปฏิบัติการหลักได้ดี
- การเชื่อมต่อกับ ecosystem เชิงคำสั่งขนาดใหญ่:
- implementation ส่วนใหญ่รองรับการเชื่อมต่อกับภาษา C ได้ดี และใช้งานผ่าน CFFI ได้
- ความเร็วขณะรัน:
- SBCL มีความเร็วขณะรันสูงมาก
- มัลติเธรด:
- มาตรฐาน Common Lisp ไม่ได้รวมการรองรับมัลติเธรดไว้อย่างชัดเจน แต่ implementation หลัก ๆ รองรับ
- มีไลบรารีชื่อ Bordeaux-Threads ที่ช่วยลดความแตกต่างระหว่าง implementation ต่าง ๆ
- ใช้ไลบรารีอย่าง lparallel, cl-async, blackbird เพื่อทำมัลติเธรดและเขียนโปรแกรมแบบอะซิงก์ได้
- คอมมูนิตี้ที่แข็งแรง:
- ผู้เขียนค้นพบกิจกรรมของคอมมูนิตี้และได้มีส่วนร่วม
- จากผลสำรวจคอมมูนิตี้ปี 2024 และงาน European Lisp Symposium ก็เห็นได้ว่าคอมมูนิตี้ Common Lisp ยังเคลื่อนไหวอย่างคึกคัก
- เครือข่ายบล็อกและ subreddit ก็เป็นแรงสนับสนุนจากคอมมูนิตี้ที่แข็งแรงเช่นกัน
- ecosystem:
- คนส่วนใหญ่ใช้ Quicklisp แต่ผู้เขียนจัดการแพ็กเกจเองด้วย OCICL
- สามารถหาไลบรารีและข้อมูลเชิงเทคนิคได้จาก Common Lisp Cookbook, CLiki, Awesome CL
- การรองรับไลบรารีเฉพาะด้าน:
- JSON: jzon
- Sqlite3: cl-sqlite
- HTTP request: dexador
- โครงสร้างข้อมูลเชิงฟังก์ชัน: FSet, cl-hamt
หมายเหตุสำหรับผู้มาใหม่
- เนื่องจากมีผู้เริ่มต้นเข้ามาใน Common Lisp Discord มากขึ้น ผู้เขียนจึงเขียนบทความนี้เพื่อแบ่งปันว่าตนเองเลือก Common Lisp และปรับตัวเข้ากับมันอย่างไร
- หวังว่าบทความนี้จะเป็นประโยชน์กับคนที่สนใจ Common Lisp
2 ความคิดเห็น
ความคิดเห็นบน Hacker News
ประทับใจกับประสบการณ์ที่แก้ปัญหาได้โดยไม่ต้องมีซอร์สโค้ดด้วยการใช้ SBCL ซึ่งถ้าเป็นเทคสแตกอื่นก็คงแก้ได้ไม่เร็วแบบนี้เมื่อไม่มีซอร์สโค้ด
แชร์ประสบการณ์การย้ายจาก Common Lisp ไป Clojure และมองว่าความสามารถด้าน concurrency ของ Clojure นั้นน่าสนใจ
การใช้ vim-slime ช่วยเพิ่มทั้งประสิทธิภาพการทำงานและความพึงพอใจของนักพัฒนาอย่างมาก
ไม่เข้าใจคุณค่าของ Lisp แต่จำเพลงที่เกี่ยวข้องได้
ยืนยันว่า Emacs/slime เป็น Lisp IDE ที่ดีกว่า vim-slime
ใช้ Common Lisp เป็นงานอดิเรก และอยากรันโค้ด C# ใน SBCL REPL
แชร์ประสบการณ์พัฒนาแอปพลิเคชัน CLI ด้วย Clojure และ babashka
เจอปัญหาเมื่อใช้ native-image และคิดว่า Clojure เป็นภาษาที่เกือบสมบูรณ์แบบ
แสดงความสนใจในภาษา Janet และกล่าวว่า README กับ FAQ ของโปรเจกต์บน GitHub มีประโยชน์
แชร์ประสบการณ์ที่ทำให้อยากเรียนรู้ Lisp โดยเฉพาะผู้เขียนที่เป็นแฟน vim ซึ่งดูน่าสนใจมาก
แม้ฉันจะยังไม่เข้าใจคุณค่าของ Lisp แต่ก็จำเพลงที่เกี่ยวข้องได้... มีเพลงเกี่ยวกับ Lisp อยู่หลายเพลง และใน YouTube ก็มีเพลงชื่อว่า Land of Lisp ;-)