Hy 1.0 – ภาษาถิ่น Lisp สำหรับ Python
(github.com/hylang)- Hy 1.0.0 ซึ่งเป็นภาษาถิ่น Lisp ที่ฝังอยู่ใน Python ได้รับการปล่อยออกมาแล้ว หลังผ่านการพัฒนาเป็นระยะ ๆ และการใช้งานจริงมาประมาณ 12 ปี
- ใน Hy 1.x การเปลี่ยนแปลงที่ทำให้ ความเข้ากันได้เสียหาย ในองค์ประกอบภาษาที่มีเอกสารกำกับ จะนำไปสู่การเพิ่มหมายเลขเวอร์ชัน major โดยยกเว้นกรณีการยุติการรองรับเวอร์ชัน Python ที่นักพัฒนา CPython ไม่รองรับแล้ว
- จุดเน้นต่อจากนี้จะอยู่ที่การแก้ บั๊ก ใหม่ ๆ การเพิ่มความเข้ากันได้กับ Python เวอร์ชันใหม่ และการ รองรับฟีเจอร์ใหม่ของ Python ในแบบที่ไม่ทำให้โค้ด Hy 1.x.y เดิมเสียหาย
- ผู้ใช้รายหนึ่งยกตัวอย่างการใช้มาโคร Hy เพื่อลดรูปการประกาศ SQLAlchemy ORM ให้อยู่ในรูป
defmodelและอธิบายว่าเพราะเป็นการขยายมาโคร จึง ไม่มีค่าใช้จ่ายเพิ่มเติมตอนรันไทม์ - การทำงานโดยตรงบน MicroPython ดูจะยากเพราะมีเพียงส่วนย่อยของไลบรารีมาตรฐาน แต่การแปลงด้วย
hy2pyบน CPython แล้วใช้เฉพาะโครงสร้างที่ MicroPython รองรับอาจเป็นไปได้
การปล่อย Hy 1.0.0
- Hy 1.0.0 ได้รับการปล่อยออกมาแล้ว
- Hy เป็น ภาษาถิ่น Lisp ที่ฝังอยู่ใน Python
- ก่อนมาถึงรีลีสนี้ มีการพัฒนาเป็นระยะ ๆ และมีการใช้งานจริงจำนวนมากมาเกือบ 12 ปี
- บทแนะนำและเอกสารมีให้ที่ Hylang.org
- ประวัติเวอร์ชันดูได้ใน NEWS file
- ยังมีลิงก์ไปยังบทความเกี่ยวกับรีลีสที่จริงจังน้อยกว่าอย่าง HYPE POST ด้วย
นโยบายความเข้ากันได้ของ 1.x
- ต่อจากนี้ breaking change ในส่วนของภาษาที่มีเอกสารกำกับ จะเพิ่มหมายเลขเวอร์ชัน major
- ข้อยกเว้นคือกรณียุติการรองรับเวอร์ชัน Python ที่นักพัฒนา CPython ไม่รองรับแล้ว
- มีการระบุเจตนาว่าจะไม่ให้การเพิ่มเวอร์ชัน major เกิดขึ้นบ่อย
- จุดเน้นของงานต่อจากนี้อยู่ที่
- การแก้ บั๊ก ที่เกิดขึ้นใหม่
- การเพิ่มความเข้ากันได้กับ Python เวอร์ชันใหม่
- การรองรับฟีเจอร์ใหม่ของ Python ในแบบที่ไม่ทำให้โค้ดที่ทำงานได้ใน Hy 1.x.y รุ่นก่อนเสียหาย
ตัวอย่างการใช้มาโคร Hy: DSL โมเดล SQLAlchemy
- ผู้ใช้รายหนึ่งอธิบายว่ากำลังสร้าง ORM และเว็บเฟรมเวิร์กแบบอะซิงโครนัสด้วย Hy โดยทั้งสองอย่างใช้ไลบรารีเดิมที่มีอยู่ และส่วนใหญ่ประกอบขึ้นด้วย มาโคร
- มีการนำเสนอตัวอย่างการเขียนประกาศโมเดลจาก SQLAlchemy ORM Quick Start Guide ให้สั้นลงด้วยมาโคร
defmodelของ Hy- เขียนโมเดล
User,Addressและการประกาศความสัมพันธ์ในรูป S-expression ของ Hy defmodelเป็นมาโครที่ขยายเป็นโค้ด SQLAlchemy จึงไม่มี ค่าใช้จ่ายเพิ่มเติมตอนรันไทม์
- เขียนโมเดล
- ผู้ใช้ระบุว่าการที่ภายในของ Hy และ API มีเสถียรภาพเป็นสิ่งจำเป็นสำหรับงานลักษณะนี้
การประกาศความสัมพันธ์และการถกเรื่อง Query DSL
- ตัวอย่าง
defmodelถูกขยายไปยังรูปแบบความสัมพันธ์หลายแบบ- one-to-one:
1->1 - many-to-many:
*->*และdeflinktable - ฟิลด์ timestamp:
:timestamp-create,:timestamp-update
- one-to-one:
- หลังประกาศแล้ว อ็อบเจ็กต์จะเป็น อ็อบเจ็กต์ SQLAlchemy 2.0 ORM ทั่วไป ดังนั้นสามารถใช้ Hy เฉพาะส่วน DSL ของสคีมาฐานข้อมูล และใช้ Python กับส่วนที่เหลือได้
- Query DSL ยังอยู่ระหว่างทำงาน และมีการกล่าวว่า fluent interface ไม่ค่อยเข้ากับ S-expression
- ความเห็นหนึ่งเสนอให้ทำให้ syntactic order กับ semantic order ของ SQL ตรงกัน พร้อมลิงก์ไปยังงานของ Google Research เรื่อง SQL Has Problems. We Can Fix Them: Pipe Syntax In SQL
- มีคำตอบว่าแนวทางอย่าง
|>หรือการเลียนแบบ list comprehension อาจเป็นไปได้ แต่ดีไซน์สุดท้ายจะออกมาหลังจากทำแอปขนาดเล็กและวนรอบรีแฟกเตอร์ซ้ำ ๆ
ความเป็นไปได้กับ MicroPython และกระแสตอบรับต่อรีลีส
- มีคำถามว่าสามารถทำงานบน MicroPython แทน CPython ได้หรือไม่
- คำตอบมีแนวโน้มว่า การทำงานโดยตรงดูจะยาก เพราะ MicroPython มีเพียงส่วนย่อยขนาดเล็กของไลบรารีมาตรฐาน Python
- อย่างไรก็ตาม หากใช้
hy2pyบน CPython เพื่อแปลงเป็นโค้ด Python แล้วจำกัดให้อยู่ในโครงสร้างที่ MicroPython รองรับ ก็อาจสามารถรันผลลัพธ์ได้ - พบว่าจำนวนผู้เยี่ยมชมไม่ซ้ำรายวันของเว็บเซิร์ฟเวอร์ที่โฮสต์ Hylang.org เพิ่มขึ้นอย่างมากในวันปล่อยรีลีส
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
ตอนแรกค่อนข้างเข้าใจยากว่า Hy แปลงเป็น Python จริง ๆ อย่างไร และก็ไม่แน่ใจด้วยซ้ำว่ามันถูกคอมไพล์หรืออินเทอร์พรีต
สุดท้ายไปเจอคำอธิบายใน Wikipedia ว่า “Hy เป็น Lisp dialect ที่ออกแบบมาให้แปลง s-expression ไปเป็น abstract syntax tree (AST) ของ Python เพื่อให้ทำงานร่วมกับ Python ได้” และดูจากโค้ดบน GitHub แล้ว ตัวคอมไพเลอร์ก็น่าจะเขียนด้วย Python เช่นกัน: https://github.com/hylang/hy/blob/master/hy/compiler.py
ถ้าในเว็บหลักอธิบายว่าเป็น “Lisp dialect ที่คอมไพล์ไปเป็น Python AST” แทน “Lisp dialect ที่ฝังอยู่ใน Python” ก็น่าจะชัดเจนกว่า เพราะการฝัง Lisp ทำได้หลายแบบ เช่น ติดอินเทอร์พรีเตอร์เข้าไป, คอมไพล์เป็น Python bytecode, หรือแปลงเป็นซอร์สโค้ด Python ซึ่งแต่ละแบบก็มีข้อแลกเปลี่ยนต่างกันมาก
โดยปกติซอร์สโค้ด Hy จะกลายเป็นอ็อบเจ็กต์ Python AST แล้วให้ Python คอมไพล์และรันมันต่อ แต่ก็สามารถแปลงอ็อบเจ็กต์ Python AST ให้กลับเป็นข้อความซอร์ส Python ได้เช่นกัน และยังทำงานข้ามกันได้ทั้งใช้ Python จาก Hy หรือใช้ Hy จาก Python: https://hylang.org/hy/doc/v1.0.0/interop
สุดท้ายทั้งหมดก็กลายเป็น Python bytecode เลยทำงานได้ดี
ดูได้ราวนาที 16:25 ของวิดีโอนี้: https://m.youtube.com/watch?v=1vui-LupKJI
ตลอดหลายปีที่ Hy เติบโตขึ้น ดูเหมือนว่ามันไม่ได้สะสม syntax sugar และกรณีพิเศษเพื่อให้ Lispy มากขึ้นและ Pythony น้อยลง แต่กลับเข้าใกล้การเป็น ชั้นนามธรรมทางไวยากรณ์แบบบาง ๆ ของชุดความสามารถใน Python มากกว่า
หรือพูดอีกแบบคือไปโฟกัสที่แก่นซึ่งเลียนแบบด้วยวิธีอื่นได้ยาก โดยเฉพาะ macro ตัวอย่างล่าสุดคือ
matchก็เป็นmatchแบบเนทีฟของ Python ตรง ๆ และไม่มี polyfill สำหรับเวอร์ชันก่อน Python 3.10 สมัยก่อนfoo?เคยเป็นกรณีพิเศษที่ถูก mangling ไปเป็นis_fooแต่ก็ถูกถอดออกแล้ว,hy.evalก็ถูกปรับให้ใกล้กับevalของ Python มากขึ้น, และยูทิลิตีที่ไม่ใช่แก่นหลักแต่มีไว้ก็ดีอย่างunlessก็มักถูกย้ายไปอยู่ในแพ็กเกจ Hyruleตอนแรกมันดูสวนทางกับสัญชาตญาณ แต่ข้อดีสำคัญคือช่วยลดเส้นโค้งการเรียนรู้เวลาย้ายจาก Python มา Hy และทำให้โต้ตอบกับแพ็กเกจ Python ได้สอดคล้องง่ายขึ้น อาจเป็นไปได้ด้วยว่าเหตุผลหนึ่งคือเพื่อให้บำรุงรักษาภาษาได้ง่ายขึ้น และถ้าจำไม่ผิด แค่
letอย่างเดียวก็เหมือนจะลองทำกันราวสี่ครั้งกว่าจะลงตัวเวลาผมเขียนโค้ด Hy ผมก็เปิดเอกสาร Python หรือเอกสารของไลบรารี Python ภายนอกบ่อยกว่าเอกสาร Hy มาก รู้สึกว่ามีหลายจุดที่ Python ควรถูกปรับปรุง แต่ฟีเจอร์เก่า ๆ อย่างการอนุญาตให้เขียน
Trueเป็นtrueเพื่อเอาใจ Clojure นั้นจริง ๆ แล้วก็เป็นแค่ความซับซ้อนที่ไม่จำเป็นHYPE POST ดีมากจริง ๆ ในฐานะคนทำซอฟต์แวร์องค์กร ต้องบอกว่า มุกเสียดสี เฉียบมาก
https://github.com/hylang/hy/discussions/2609
ในที่สุดก็ออกสักที แบบนี้คงได้ไปเก็บงาน https://github.com/rcarmo/sushy ต่อ
ผมค่อย ๆ แตะมันมาเป็นปี ๆ แต่ทุกครั้งที่อัปเกรด Hy ก็มักมีบางส่วนของไวยากรณ์พัง หรือไม่ก็มีฟีเจอร์ย้ายเข้าออกแพ็กเกจ Hyrule ทำให้ลำบาก
อนึ่ง Hy ทำงานได้ค่อนข้างดีใน https://holzschu.github.io/a-Shell_iOS บน iPad ด้วย เพียงแต่ syntax highlighting ของ vim/neovim ต้องตามให้ทันรีลีส 0.29+ และ async
ที่ผ่านมาผมก็ลอง Fennel กับ Guile มาเหมือนกัน แต่การเข้าถึงไลบรารีและ ecosystem ของ Python ยังดูดีกว่า และด้วย async ก็ทำงานด้าน API ได้อย่างมีประสิทธิภาพด้วย ใน Scheme หลายตัว การจัดการ HTTPS พร้อมการ reuse socket และควบคุม header แบบละเอียดก็ยังยุ่งยากอยู่มาก เลยรู้สึกว่าการใช้ aiohttp ดีกว่ามาก
ถ้าเทียบกับจุดเริ่มต้นเรียบง่ายในวันแรก ๆ มันมาไกลมากจริง ๆ
ผมเคยดู lightning talk ที่ PyCon ซึ่งเป็นครั้งแรกที่ Hy ถูกนำเสนอให้โลกเห็น และไม่นานหลังจากนั้นก็ได้เจอ Paul แล้วเริ่มมีส่วนร่วมกับ Hy เวอร์ชันแรก ๆ ผมดูแล
kwargsสไตล์ Common Lisp, งานภายในบางส่วน, และไลบรารีหนึ่งหรือสองตัวความขี้เล่น นั้นมีประโยชน์ โดยเฉพาะในแง่ของการรักษาแพสชันไว้ ผมชอบที่แฮกเกอร์ยังเป็นแฮกเกอร์ได้ และไม่จำเป็นที่ทุกอย่างต้องเป็นเรื่องธุรกิจ แม้ผมจะไม่ได้เกี่ยวข้องมาหลายปีแล้ว แต่ก็รู้สึกดีที่เห็นโปรเจกต์ยังเดินหน้าต่อ และนี่เป็นหมุดหมายที่ยอดเยี่ยมจริง ๆ
ถ้าเป็นแฟน Clojure ก็ยังมี Basilisp ซึ่งเป็น Lisp dialect ที่ใกล้เคียงกับ Clojure มากกว่าและรองรับ Python 3.8+ ด้วย
https://github.com/basilisp-lang/basilisp
แม้จะไม่ใช่ Lisp แต่ถ้ามองว่าเป็นภาษาการเขียนโปรแกรมเชิงฟังก์ชันที่ transpile ไปเป็น Python แล้ว Coconut ก็น่าสนใจเช่นกัน: https://coconut-lang.org/
อยากรู้ประสบการณ์จากคนที่เคยใช้ Hy หรือ Coconut จริง ๆ มาก
ด้านบนของโค้ดที่สร้างขึ้นจะมีฟังก์ชันช่วยแบบ hardcode ติดมาจำนวนมาก และโปรแกรมก็ช้ากว่าการเขียนเนื้อหาเดียวกันด้วย Python แบบธรรมดามาก
ในทางกลับกัน Hy สร้างโค้ดที่ค่อนข้างใกล้กับโค้ด Python ที่คนอาจเขียนด้วยมือ ยกเว้นเรื่องชั้นทางอ้อมเล็กน้อยที่เกิดจากการจัดการสโคปของ
letหรือความต่างบางอย่างรอบ ๆ ค่าที่คืนกลับมา ทั้งนี้ Coconut ก็ผ่านมานานแล้ว อาจจะดีขึ้นก็ได้ยินดีด้วย มีสองอย่างที่สงสัย: รองรับ การพัฒนาแบบ REPL-driven ไหม เช่น มี condition system หรือ breakloop อะไรแบบนั้นหรือเปล่า
อีกอย่างคือมี distribution แบบ standalone ไหม เพราะการแจกจ่าย Python เองก็ค่อนข้างยุ่งยาก ดังนั้นในอุดมคติแล้วถ้าสามารถแจกจ่ายเป็นไบนารี Hy ไฟล์เดียวที่รวม dependency ทั้งหมดไว้ได้ก็น่าจะดี จะเป็น static link หรือไฟล์ zip ที่แตกไปยังไดเรกทอรีชั่วคราวก็ได้
uvx hy@1.0.0ถ้ารัน
echo '(print "hi hn")' > hi.hyแล้วตามด้วยuvx hy@1.0.0 hi.hyก็จะพิมพ์"hi hn"ออกมาhttps://docs.astral.sh/uv/guides/tools/#running-tools
และ uv ก็สามารถติดตั้งและจัดการเวอร์ชัน Python ได้ด้วย
ไม่มี distribution แบบ standalone
ถ้าต้องการดีบักโค้ดแบบโต้ตอบ สามารถใส่
(.run (hy.REPL :locals {#\* (globals) #\* (locals)}))ลงในโค้ดที่ต้องการดีบักได้ และใน Python ก็ใช้ได้ในลักษณะimport hy; hy.REPL(locals = {\*globals(), \*locals()}).run()แต่เช่นเดียวกับ
code.interact()ต่อให้เปลี่ยนตัวแปร local ภายใน REPL ก็จะไม่กระจายกลับไปยังสโคปเดิมpy2appและการแฮ็กอย่างระมัดระวังสามารถคอมไพล์ทุกอย่างเป็น bytecode แล้วใช้ เครื่องมือแจกจ่ายแบบไฟล์เดียว ของ Python ได้
แต่ไม่มี condition system หรือ handlers/restarts
ชอบส่วนที่จริงจังน้อย ๆ มาก อยากให้โปรเจกต์เขียนโปรแกรมอื่น ๆ เปิดรับ ความขี้เล่น มากกว่านี้
บางทีนั่นอาจเป็นวิธีที่ดีที่สุดในการให้เกียรติขนบของ Python ก็ได้
แต่พอถึงจุดหนึ่งก็รู้สึกว่าไปไกลเกินไป เลยช่วงหลัง ๆ พยายามใส่ความขี้เล่นกลับเข้ามาอีกเล็กน้อย
ใช้ Hy แบบเป็นครั้งคราวมาเรื่อย ๆ และตอนที่พยายามสร้าง transformer ก็ได้ปล่อย https://github.com/kunalb/orphism ที่เขียนด้วย Hy ออกมาด้วย
ดูเหมือนว่าจะถึงเวลาหยิบมันกลับมาลองรันอย่างจริงจังอีกครั้งแล้ว