let-go - ภาษาในตระกูล Clojure ที่สร้างด้วย Go และเริ่มทำงานใน 7ms
(github.com/nooga)- let-go เป็นภาษาถิ่นของ Clojure ที่เขียนด้วย Go มีทั้งคอมไพเลอร์เป็นไบต์โค้ดและสแตก VM ทำงานได้เป็น ไบนารีเดี่ยวขนาดประมาณ 10MB โดยไม่ต้องพึ่ง JVM
- การเริ่มทำงานแบบ cold start อยู่ที่ประมาณ 7ms และระบุความเข้ากันได้กับ Clojure ตาม jank-lang Clojure test suite ว่า ผ่าน 4696 / 4921 assertions (95.4%)
- ผู้เขียนใช้งานกับ CLI, สคริปต์ และเว็บเซิร์ฟเวอร์ อีกทั้งยังสร้าง daemonless container runtime บน let-go และสามารถคอมไพล์เป็นไบนารีแบบ standalone หรือหน้าเว็บ WASM แบบ self-contained ได้
- เป้าหมายคือรองรับความสามารถของ Clojure จำนวนมาก เช่น persistent data structures, lazy seqs, transducers, protocols, records, multimethods, core.async, BigInts รวมถึงมี interop แบบสองทางกับฟังก์ชัน·struct·channel ของ Go
- ไม่ใช่ drop-in replacement ของ JVM Clojure และไม่โหลด JAR ดังนั้นโปรเจ็กต์จริงที่มีการพึ่งพาไลบรารีอาจต้องมีการปรับแก้
- บนเบนช์มาร์ก Apple M1 Pro ระบุว่ามีขนาดไบนารี 10MB, เวลาเริ่มต้น 6.7ms, หน่วยความจำขณะ idle 13.5MB ซึ่งชี้ให้เห็นความได้เปรียบด้านหน่วยรันที่เล็กกว่าเมื่อเทียบกับ Babashka, Joker, go-joker, gloat และ Clojure JVM
- สำหรับงานคำนวณเชิงตัวเลขขนาดใหญ่ go-joker ที่มี WASM JIT หรือ JVM ที่ HotSpot วอร์มแล้วจะทำได้ดีกว่า ขณะที่ let-go ให้ผลใกล้เคียง Babashka ในเบนช์มาร์กอัลกอริทึมส่วนใหญ่ และสรุปว่าเร็วกว่า upstream Joker มากกว่า 10 เท่า
- เนมสเปซมาตรฐานประกอบด้วย
clojure.core,clojure.string,clojure.set,clojure.edn,clojure.test,clojure.core.async,io,http,json,transit,os,System,syscall,podsเป็นต้น - สามารถโหลด Babashka pods ได้ จึงใช้งานระบบนิเวศของ pod สำหรับ SQLite, AWS, Docker, file watching ฯลฯ ได้ และแชร์
~/.babashka/pods/ร่วมกับbb - ข้อจำกัดที่ทราบแล้วรวมถึงยังไม่รองรับ Refs / STM, Agents, hierarchies, reader tagged literals,
deftype,reify,clojure.spec,alter-var-root,subseq/rsubseqและยังไม่มีการตรวจจับ int64 overflow แบบอัตโนมัติ - ความแตกต่างด้านพฤติกรรมคือบล็อก
goไม่ได้เป็น IOC state machine แต่เป็น goroutine จริง, regex ใช้re2ของ Go แทน Java regex และระบบตัวเลขประกอบด้วยint64+float64+BigInt - การติดตั้งทำได้ผ่าน Homebrew สำหรับ macOS/Linux, Releases สำหรับ Linux·macOS·Windows บน amd64/arm64 หรือใช้
go install github.com/nooga/let-go@latestบน Go 1.22+ lgรองรับ REPL, การ eval expression และการรันไฟล์ รวมถึงการคอมไพล์เป็นไบต์โค้ด.lgb, การ bundle เป็น executable แบบ standalone และการสร้างเว็บแอป WASM- เอาต์พุต WASM ประกอบด้วย
index.htmlแบบ self-contained ที่รวม WASM inline ขนาดประมาณ 6MB gzipped และ service worker โดยเมื่อใช้เนมสเปซtermจะมีเทอร์มินัลอีมูเลชันที่อิงกับ xterm.js - เซิร์ฟเวอร์ nREPL ในตัวทำงานร่วมกับ CIDER, Calva, Conjure และในโปรแกรม Go สามารถฝัง let-go เป็นชั้นสคริปต์ผ่าน
pkg/apiเพื่อส่งค่า·ฟังก์ชัน·struct·channel ของ Go เข้าไปยัง VM ได้
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
ดีเลย! ช่วงนี้ผมลองทำการทดลองเอาไวยากรณ์แบบ Lisp มาครอบบน semantics ของ Go ดูด้วย: https://codeberg.org/veqq/Joe
ถ้าเป็นสายตระกูล Clojure ที่ไม่มี JVM, Janet ก็ดีมากจริงๆ และผมก็ใช้งานในโปรดักชันอยู่พักหนึ่งแล้ว: https://janet-lang.org/
ถ้าอยากได้ Lua VM และไลบรารี ก็มี Fennel ด้วย
ลอง Wasm browser REPL นี้ดูก็ดี: https://gloathub.org/repl/
Gloat เป็นเครื่องมืออัตโนมัติสำหรับ Glojure AOT
เมื่อฤดูร้อนที่ผ่านมา ผมทำให้ Glojure AOT เป็นไปได้ร่วมกับ James Hamlin และตั้งแต่นั้นมาก็พัฒนาต่อเนื่องอยู่ กำลังทำงานร่วมกับ marcingas(nooga) ด้วยเพื่อให้ Gloat/Glojure/let-go ทำงานร่วมกันได้อย่างราบรื่น
น่าทึ่งที่มันรันบน Plan 9 ได้
ถ้า Go กลายเป็นภาษาชั้นหนึ่งบน 9front หรือก็คือเป็นภาษาที่มีมาให้ในระบบเลยก็คงเจ๋งมาก
ผมกำลังเล่นกับโซเชียลเน็ตเวิร์กสำหรับ Plan 9 อยู่: https://youtube.com/watch?v=q6qVnlCjcAI&si=MBCeM0QdA0WsKAe7
ทั้งหมดเขียนด้วย rc และ awk แต่ก็มีบางจุดที่รู้สึกว่าน่าจะดีถ้ามี Go หรือ Clojure แทรกอยู่บ้าง
amd64 ทดสอบบน 9front แล้ว และดูเหมือนว่าทุกอย่างจะทำงานได้ดี แม้ CLI จะยังไม่ค่อยมีความเป็น Plan 9 เท่าไร แต่สักวันก็อยากพอร์ตให้เนทีฟกว่านี้
ตอนนี้มี Clojure สำเนียง Go อยู่หลายตัวแล้ว สิ่งที่ผมอยากรู้ที่สุดคือฝั่งไหนที่ โฮสต์บน Go อย่างสมบูรณ์ และให้ระดับการทำงานร่วมกันได้เทียบเท่ากับที่ JVM Clojure มีกับ Java
อยากให้ของที่ผมทำใน Go เอาไปใช้ได้ และใน Clojure ก็ใช้ Go ได้ด้วย รวมถึงทำโปรเจกต์แบบผสมกันได้ อีกอย่างนอกจากเรื่อง interop แล้ว ก็อยากเห็นรายละเอียดที่สรุปว่ามีอะไรที่เหมือนและต่างกันอย่างไร
ส่วน let-go สามารถส่งผ่านค่า Go แบบไป-กลับได้ทุกชนิด รวมถึง struct, function และ channel แต่ยังไม่สามารถดึงไลบรารี Go แบบใดก็ได้เข้ามาใช้ตรงๆ โดยไม่ต้องห่อหุ้ม ไลบรารีพวกนั้นต้องถูก build ไว้ในรันไทม์ก่อน
ขอทักเล็กน้อยว่าใน README บอกว่า cold start 7ms แต่ไม่กี่บรรทัดถัดมาดันบอก 6ms สงสัยยิ่งอ่าน README ก็ยิ่งเร็วขึ้นมั้ง
นี่คือ Clojure port แบบที่ผมตามหาอยู่เสมอ
เพราะผมมองว่า core library และ channel abstraction ของ Go เป็น API พื้นฐานที่เรียบง่ายและดีกว่า และก็น่าจะเข้ากันได้ดีกับ API สาย core.async ด้วย แถมยังตอบโจทย์ความอยากได้ไบนารีเดี่ยวขนาดใหญ่ด้วย
ขอบคุณสำหรับงานนี้ ถ้าความหลงใหลใหม่ที่ผมมีต่อ C++26 ซาลงหน่อย จะกลับมาดูอีกแน่นอน
อีกอย่าง ผมก็ไม่รู้ว่าทำไม Glojure ถึงไม่เคยอยู่ในเรดาร์ของผมเลย และมันก็ดูเป็นโปรเจกต์ที่ยอดเยี่ยมเหมือนกัน
ที่เรียกว่า PHP ยุคเก่า เพราะเดิมที PHP ใกล้เคียงกับการเป็น DSL ที่เน้นเว็บมากกว่า เดี๋ยวนี้ไม่ค่อยเป็นแบบนั้นแล้ว ภาษาแบ็กเอนด์ที่เขียนง่ายคล้าย PHP แต่มีพลังของ Go อยู่ด้านหลังน่าจะน่าสนใจ และ Clojure ก็เป็นตัวเลือกที่ยอดเยี่ยม
อีกทางเลือกคือ Joker ด้วย: https://joker-lang.org
มันยอดเยี่ยมมากจริงๆ และผมคิดว่ามัน ถูกประเมินต่ำไปมาก
แต่สำหรับ let-go ผมไม่อยากใส่อะไรเพิ่มมากเกินไป ผมชอบที่มันยังอยู่ภายใน 10MB ได้
อยากให้ชื่อภาษาดีกว่าแค่ “lets-go” หน่อย “clogo” เป็นไง?
(let [...] (go ...))มันทำให้ใช้ let ใน Go ได้!
ส่วน Clogo สำหรับผมถือว่า no-go ถ้ามีชื่ออื่นที่ดีกว่านี้ก็ยินดีพิจารณา
ถ้าส่ง PR ไปที่ https://github.com/chr15m/awesome-clojure-likes จะยินดีมาก