Lisp: आइसिंग है या केक?
(dthompson.us)- Spring Lisp Game Jam 2024 में 48 गेम सबमिट हुए, जिससे नया रिकॉर्ड बना, और एंट्रीज़ साफ़ तौर पर दो तरीकों में बंटी दिखीं: Lisp को ऊपर से चढ़ाने वाला तरीका और पूरे stack को ही Lisp से बनाने वाला तरीका
- आइसिंग वाला तरीका C/Rust/Lua आधारित प्रोग्राम के ऊपर Lisp को scripting layer की तरह रखकर जल्दी नतीजे देता है, लेकिन नीचे की static languages और toolchain से मज़बूती से बंधा रहता है
- केक वाला तरीका प्रोग्राम का ज़्यादातर हिस्सा Lisp में लिखता है और C FFI को न्यूनतम रखकर गहरा control देता है, लेकिन library implementation, wrapper लिखने और web deployment में लागत बढ़ जाती है
- Game Jam में Fennel+love2d और S7+raylib आइसिंग के करीब हैं, Guile+Chickadee केक है, और Hoot+HTML5 canvas Scheme-आधारित Wasm toolchain की वजह से केक के अधिक करीब है
- Lisp का हिस्सा जितना बढ़ता है, live hacking, memory safety, Lisp/C boundary में कमी और hackability उतनी बढ़ती है; Guix, Trial और Pre-Scheme जैसे प्रोजेक्ट भी यही दिशा दिखाते हैं
Spring Lisp Game Jam 2024 में submissions की स्थिति
- Spring Lisp Game Jam 2024 एक हफ्ते पहले खत्म हुआ, और 48 गेम सबमिट हुए, जिससे jam का नया रिकॉर्ड बना
- इसके बाद प्रतिभागियों ने एक हफ्ते तक एक-दूसरे के गेम खेले और उनका मूल्यांकन किया
- submissions का language-wise distribution इस प्रकार है
- Guile: 15, 31%
- Fennel: 10, 21%
- Clojure: 5, 10%
- Common Lisp: 5, 10%
- Racket: 4, 8%
- Elisp: 4, 8%
- S7: 3, 6%
- Kawa: 1, 2%
- Owl: 1, 2%
- Guile का हिस्सा: {p:31}
- Scheme implementations को एक ही
schemecategory में न रखने की वजह यह है कि Scheme specification छोटा है, और Guile, Racket, S7, Kawa अलग-अलग उद्देश्यों के implementations हैं - इस jam में Guile ने पहली बार सबसे ज़्यादा submissions दर्ज किए
- 15 Guile games में से 11 Hoot से बने web games हैं
- Hoot, Spritely Institute में विकसित हो रहा Scheme-to-WebAssembly compiler है
- इन 11 में से 2 official Spritely projects हैं
- Spritely Institute ने jam शुरू होने से पहले लोगों से Hoot से game बनाने का अनुरोध किया था, और कई प्रतिभागियों ने इसे अपनाया
- आम तौर पर इस jam में सबसे लोकप्रिय language Fennel होती है, जो Lua में compile होने वाली Lisp है
- S7 का इस्तेमाल करने वाले 3 games भी Lisp को game development में इस्तेमाल करने के तरीकों से जुड़े उदाहरण हैं
Lisp को आइसिंग की तरह इस्तेमाल करने का तरीका
- आइसिंग pattern वह approach है जिसमें C, Rust जैसी static languages से बने “केक” के ऊपर Lisp को scripting language की तरह रखा जाता है
- आम तौर पर बड़े program के अंदर Lisp interpreter embed किया जाता है
- अगर आप application के high-level हिस्से Lisp में लिखना चाहते हैं, तो यह सबसे तेज़ रास्ता हो सकता है
- इसके लिए उपयुक्त interpreter या compiler चाहिए
- application में ज़रूरी hooks जोड़ने का तरीका भी होना चाहिए
- अगर program का मुख्य हिस्सा C या Rust में लिखा है, तो उसे emscripten से WebAssembly में compile करके web पर deploy किया जा सकता है
- जल्दी संतोषजनक नतीजे मिल सकते हैं, लेकिन यह static language और उसके toolchain से काफ़ी tightly coupled रहता है
- प्रमुख उदाहरण ये हैं
- S7 embed किया जा सकने वाला Scheme है
- Guile को भी C programs को extend करने के लिए इस्तेमाल किया जा सकता है, लेकिन executable के अंदर interpreter डालने के बजाय आम तौर पर
libguileसे dynamically link किया जाता है - Fennel Lua extension points वाली मौजूदा applications का इस्तेमाल करके Lisp जैसी language को Lua में compile करता है
Lisp को केक की तरह इस्तेमाल करने का तरीका
- केक pattern वह approach है जिसमें software stack का जितना संभव हो उतना हिस्सा Lisp में implement किया जाता है
- Lisp को किसी non-Lisp program के अंदर डालने के बजाय, program का ज़्यादातर हिस्सा Lisp में लिखा जाता है
- ज़रूरत पड़ने पर foreign function interface (FFI) से shared libraries call की जाती हैं, लेकिन बेहतर है कि इसका इस्तेमाल न्यूनतम रहे
- नतीजा आने में ज़्यादा समय लगता है
- चुने हुए Lisp implementation में जो libraries नहीं हैं, उन्हें खुद implement करना पड़ता है
- जिन C shared libraries से बचना संभव नहीं है, उनके wrappers लिखने पड़ते हैं
- project आसानी से emscripten target नहीं बनता, इसलिए web deployment ज़्यादा मुश्किल हो जाता है
- यह approach classic embed vs. extend debate से जुड़ती है
- Guile को आइसिंग के रूप में भी इस्तेमाल किया जा सकता है, लेकिन केक की तरह इस्तेमाल करने पर इसकी ताकत ज़्यादा दिखती है
- Guile की शुरुआती vision यह थी कि Scheme interpreter जोड़कर दूसरे programs को Emacs जैसा बनाया जाए
- आज की अच्छी practice यह है कि program को शुरू से Scheme में लिखा जाए
- Common Lisp भी केक approach का अच्छा उदाहरण है
- SBCL जैसे implementations अच्छा C FFI देते हैं
- यह efficient native executables में compile हो सकता है, जिससे performance के कारण C इस्तेमाल करने की इच्छा वाली स्थितियां कम हो जाती हैं
Game Jam examples में आइसिंग और केक
-
Fennel + love2d
- love2d लंबे समय से solo या छोटी teams के game development के लिए लोकप्रिय विकल्प रहा है
- love2d Lua interpreter embed करने वाला C++ program है, इसलिए Fennel के लिए अच्छा target है
- ज़्यादातर Linux distributions love2d को package करते हैं, इसलिए
.lovefiles को native रूप से चलाना आसान है - emscripten की वजह से love2d games को web पर भी deploy किया जा सकता है
- इसलिए ज़्यादातर Fennel games love2d का इस्तेमाल करते हैं
- ./soko.bin और Gnomic Vengeance इसी stack का इस्तेमाल करते हैं
- Fennel+love2d Lisp as icing का पूरा उदाहरण है
- Fennel stack के सबसे ऊपर है, और Lisp को नीचे की layers में फैलाने का रास्ता वास्तव में नहीं है
- अभी तक यह सबसे सफल Lisp game development stack है
-
S7 + raylib
- इस jam में GhostHop और Life Predictor दो games ने S7+raylib stack इस्तेमाल किया
- Raylib C library है जिसके कई high-level language bindings हैं, और हाल के वर्षों में इसकी लोकप्रियता बढ़ी है
- S7 भी C में implement है और आसानी से embed हो सकता है, इसलिए यह combination emscripten से web पर deploy करना आसान बनाता है
- S7+raylib भी Lisp as icing का उदाहरण है, और देखने लायक है कि भविष्य के jams में यह और लोकप्रिय होता है या नहीं
-
Guile + Chickadee
- Chickadee Guile के लिए game library है, और rendering सहित लगभग सभी दिलचस्प हिस्से Scheme में implement करती है
- हाल के jams में Turbo Racer 3000 और Bloatrunner दो games Chickadee से बनाए गए
- Guile+Chickadee Lisp as cake का उदाहरण है
- Chickadee image, audio, font loading जैसे low-level कामों के लिए कुछ C libraries को wrap करता है, लेकिन इसका अपना code pure Scheme में लिखा है
- matrix और vector math भी पूरा Scheme में implement है
- यह love2d और raylib की टक्कर का rendering primitives set देता है, और यह भी Scheme में implement है
- जहां कई दूसरी Lisp game libraries nanosvg जैसी C libraries इस्तेमाल करती हैं, वहीं Chickadee ने Scheme में vector graphics rendering implement करने में भी प्रगति की है
- Chickadee ने Guile compiler और virtual machine की सीमाओं को push किया, और इस प्रक्रिया में Guile भी बेहतर हुआ
- हालांकि इसे ज़्यादातर एक व्यक्ति ने सीमित खाली समय में विकसित किया है, इसलिए अधिक लोकप्रिय game development libraries के बराबर features तक पहुंचने में लंबा समय लगता है
- मौजूदा स्थिति में भी यह अपने उद्देश्य के लिए काफ़ी अच्छी तरह काम करता है
-
Hoot + HTML5 canvas
- Hoot Scheme-to-WebAssembly compiler है
- Hoot, C में लिखी Guile VM को emscripten से Wasm में compile नहीं करता
- इसके बजाय यह पूरा Wasm toolchain और Guile compiler के लिए नया backend implement करता है जो सीधे Wasm emit करता है
- Hoot पूरा Scheme में लिखा है
- emscripten से compile किए गए C programs जहां linear memory आधारित Wasm 1.0 target करते हैं, वहीं Hoot GC-managed heap types वाले Wasm 2.0 को target करता है
- इस structure की वजह से Hoot binaries garbage collector को साथ में deploy नहीं करतीं
- इसलिए यह emscripten से compile किए गए Lisp runtime से काफी छोटी होती हैं
- एक Hoot game की Wasm binary 2MiB से कम है, और जांचे गए love2d game का
love.wasmलगभग 6MiB था - Hoot programs JavaScript के साथ आसानी से interoperate करते हैं
- Scheme objects को JavaScript में आसानी से pass किया जा सकता है
- JavaScript objects को भी Scheme में pass किया जा सकता है
- क्योंकि दोनों तरफ के objects एक ही heap में manage होते हैं
- Browser APIs को Wasm import से access किया जा सकता है, इसलिए games में built-in HTML5 canvas API आसान 2D rendering option बनती है
- इस jam में Hoot इस्तेमाल करने वाले 11 games थे, जिनमें Cirkoban और Lambda Dungeon भी शामिल हैं
- Hoot+HTML5 canvas ज़्यादातर मोटा केक है, जिसमें थोड़ी आइसिंग मिली हुई है
- Hoot bootstrapping में 1 साल और अच्छा-खासा funding लगा
- emscripten इस्तेमाल किए बिना अपना toolchain बनाया गया, और Guile compiler को भी extend किया गया
- Guile VM पर चलने वाला Wasm interpreter भी है
- दूसरी तरफ canvas API बहुत high-level है
- केक के और करीब वाला तरीका Hoot की JS FFI से WebGL या WebGPU call करना है
- भविष्य की योजना WebGL/WebGPU की तरफ है, और इसे संभव बनाने के लिए Wasm GC improvements की ज़रूरत है
- एक और लक्ष्य Chickadee को Hoot पर port करना है, ताकि Chickadee games को love2d games की तरह native और browser दोनों में आसानी से खेला जा सके
केक approach की सीमाएं और फायदे
- केक approach की सीमाएं भी साफ़ हैं
- आधुनिक environment Lisp machine की दुनिया नहीं है, और सबसे ऊंचा Lisp cake भी अक्सर C से बने बड़े cake के ऊपर रखा होता है
- आधुनिक Lisp systems किसी न किसी बिंदु पर नीचे की layers तक पहुंचते हैं
- Emacs C core के ऊपर है
- Guile VM C में लिखी है
- Hoot, V8 जैसे C++ आधारित बड़े JavaScript engine के ऊपर चलता है
- Hoot games फिलहाल WebGL/WebGPU नहीं, बल्कि HTML5 canvas से render करते हैं
- OpenGL इस्तेमाल करने के लिए
libGLचाहिए - Chickadee
guile-openglइस्तेमाल करता है, जो C FFI सेlibGLcall करता है libpng, FreeType आदि भी मौजूद हैं
- सब कुछ Lisp में फिर से लिखने के लिए resources की बड़ी समस्या है
- फिर भी stack के कुछ हिस्से C जैसी languages से वापस हासिल करना एक छोटी जीत है
- Lisp में लिखे हिस्सों को hack करना आसान होता है, और कुछ में program चलते समय live hacking भी संभव है
- GC-managed runtime की वजह से आम तौर पर memory safety मिलती है
- FFI calls कम होने से Lisp/C boundary पार करने का overhead घटता है और safety भी बढ़ती है
- stack में Lisp का हिस्सा जितना बढ़ता है, वह आइसिंग के बजाय केक के उतना करीब हो जाता है
games के बाहर केक के उदाहरण
- Guix दिखाता है कि केक approach कितनी शक्तिशाली हो सकती है
- Guix ने Nix project का functional packaging model लेकर उसे नए सिरे से implement किया और Nix language को Guile से replace किया
- इसकी वजह code staging, code sharing और hackability में सुधार है
- Guix systemd के बजाय Guile में लिखे init system का भी इस्तेमाल करता है, और यह चुनाव भी इन्हीं वजहों से आया
- शुरुआत में Guix पर बिना वजह पहिया फिर से बनाने की आलोचना होना आसान था, लेकिन 10 साल बाद Lisp usage को maximize करने की यही जिद project की सफलता की कुंजी बन गई
- users Guix idioms और थोड़ी Guile सीखकर operating system को अपनी पसंद के अनुसार configure करने की शक्तिशाली क्षमता हासिल करते हैं
- Guix को आधुनिक hardware पर Lisp machine के सबसे करीब का experience माना जा सकता है
- Common Lisp की तरफ Trial game engine एक उदाहरण है, जिसने C libraries को wrap करने के बजाय कई हिस्से Common Lisp में implement किए हैं
- Pre-Scheme जैसे projects उम्मीद देते हैं कि GC-managed runtime के नीचे की layers भी किसी दिन Lisp में implement की जा सकती हैं
- Pre-Scheme को Scheme 48 में develop किया गया और सफलतापूर्वक इस्तेमाल किया गया
- NLnet grant की वजह से आधुनिक revival की उम्मीद है
Lisp से stack का और बड़ा हिस्सा बनाने की दिशा
- दिशा केक की तरफ अधिक है
- ऐसे और projects की ज़रूरत है जो Lisp क्या कर सकता है, इसकी सीमाओं को लगातार push करें
- Lisp Game Jam में सबसे दिलचस्प चीज़ games खुद नहीं, बल्कि पुराने और सूखे C से cake का एक टुकड़ा वापस हासिल करने की छोटी प्रगति है
- Guile game development में Chickadee project के जरिए सीमाओं को लगातार push करने की कोशिश है
- निष्कर्ष Rust में फिर से लिखना नहीं, बल्कि Lisp में फिर से लिखना है
1 टिप्पणियां
Hacker News की राय
आजकल software approaches की तुलना वस्तुनिष्ठ ढंग से करने वाले लेख बहुत कम दिखते हैं, इसलिए यह और भी अच्छा लगा
ऐसे लेख खोजने की कोशिश भी करें तो आजकल search results अक्सर SEO spam से आगे नहीं निकल पाते
Janet जैसे गेम्स के लिए बनाया गया लगता है और web server या graphics जैसे “batteries included” elements भी हैरानी की बात है कि काफी लगते हैं, लेकिन Janet इस्तेमाल करने वाले गेम्स न दिखना थोड़ा चौंकाने वाला था
Lisp और games के संदर्भ में यह एक बार देखने लायक भाषा लगती है
s7 को ध्यान मिल रहा है, यह अच्छा लगा
Max/MSP computer music environment में Scheme interpreter जोड़ने वाले open-source extension Scheme for Max में मैंने Scheme के तौर पर इसे इस्तेमाल किया, और यह Guile, Clojure, Common Lisp के बीच कहीं है, फिर भी बहुत छोटा और embed करने में आसान है
Guile से कहीं ज्यादा उदार BSD license होना भी अच्छा है
अगर आपको first-class environments वाले Common Lisp macros पसंद हैं, तो s7 भी पसंद आने की संभावना ज्यादा है
WASM में भी इसे इस्तेमाल करना बहुत आसान था, और मैं इसे एक music education project में इसी तरह इस्तेमाल कर रहा हूं
Scheme से JS functions call करने और उल्टा JS से Scheme call करने के लिए generic functions बनाना भी मुश्किल नहीं था, इसलिए पूरा flow smooth रहा
iOS और Android की native apps में graphics को छोड़कर engine के रूप में s7 और SQLite को सफलतापूर्वक embed किया
यह बहुत तेज, अच्छे FFI वाला, stable और छोटा था, और mobile apps के बीच shared code, बेहद तेज unit tests, और साफ toolchain से काफी फायदा मिला
आखिर में mobile पर हमने ज्यादा practical Lisp, Fennel, की ओर move कर लिया
mobile पर s7 इस्तेमाल करने वाली team लगभग सिर्फ हमारी ही थी, जबकि Lua mobile extension language के रूप में कहीं ज्यादा आम था, और r7rs Scheme compatibility की स्थिति का भी असर पड़ा
desktop development में Guile और deployment में s7 इस्तेमाल करने पर subtle incompatibilities, जैसे parameter evaluation order, अक्सर अटकाती थीं
s7 और Fennel दोनों के पास बेहतरीन projects और communities हैं
Spritely Institute को, खासकर उसके blog तक, जरूर देखने की सलाह दूंगा
यह जगह क्या करती है, इसका spoiler नहीं देना चाहता, लेकिन यह गहराई से explore करने लायक विषय और संस्था है
blog, related links और projects पढ़ने में ही मैंने 10 घंटे से ज्यादा लगाए
https://spritely.institute/archive/
“हम Lisp machines की दुनिया में नहीं, बल्कि महिमामंडित PDP-11 की दुनिया में रहते हैं” वाला सार प्रभावशाली है
लेकिन sdl के साथ इस्तेमाल होने वाली “icing” भी है या नहीं, यह जानने की उत्सुकता है
tag-less memory इस्तेमाल करने वाली von Neumann machine होने के लिहाज से समानता है, लेकिन 32-bit microprocessors के आम होने और Lisp compiler technology के उसी हिसाब से विकसित होने वाले 80 के दशक के मध्य के आसपास से traditional CPUs ने Lisp machines को पीछे छोड़ना शुरू कर दिया था
“tag-less memory” वाला हिस्सा भी CHERI जैसी trends को देखें तो शायद हमेशा बना न रहे, और LispM-style architecture की बड़ी वापसी की गुंजाइश है
कई साल तक living room में PDP-11/45 रखा था, फिर बाद में जगह बचाने के लिए 8-inch floppy drives वाली कुछ H-11 LSI-11/2 machines से बदल दिया
PDP-11 सिर्फ Unix का primordial form ही नहीं था, बल्कि conceptually अच्छी तरह design किया गया था
जैसे हम “एक screen में आ जाने वाली” routines पसंद करते हैं, वैसे ही PDP-11 का छोटा direct address space बहुत बड़े न होने वाले modules को प्रेरित करता था और modularity को बढ़ावा देता था
आज के लिए क्या यह कम पड़ता है? बिल्कुल, खासकर big data के लिए तो दर्दनाक है
फिर भी PDP-11 सफल हुआ और आज भी उसके निशान बचे हैं, इसके पीछे conceptual वजहें हैं
C को ठीक करने का कोई दूसरा तरीका नहीं है, और ऐसा code बहुत ज्यादा है जो फिर से लिखा नहीं जाएगा
Lisp मुख्यतः lists से काम करता है, और lists memory में इधर-उधर pointers follow कर सकती हैं
पुराने CPUs में memory का random access time आम तौर पर समान होता था, इसलिए यह समस्या नहीं थी, लेकिन modern CPUs memory pointers को उसी speed से follow नहीं कर सकते और performance के लिए locality rules का पालन करना पड़ता है
इसलिए C या Fortran arrays जैसी चीजें इस्तेमाल करने वाले algorithms Lisp list-based versions से हमेशा तेज होंगे
हाल में Guile Scheme की प्रगति से उम्मीद जगी है
पिछली बार देखने से अलग, यह interpreted language से proper compiler वाली language बन गई है, और अब Hoot के साथ WASM compilation भी संभव हो गया है
Clojure, uLisp, Common Lisp से परिचित हूं, लेकिन Guile Scheme ऐसा लगता है जैसे Common Lisp की बहुत-सी extra baggage हट गई हो, और खासकर अगर Guix और Shepard जम जाते हैं तो compiled Lisp अपने हाथ में रखना चाहूंगा
Little Lisper और SICP के अलावा Guile Scheme को प्रभावी ढंग से सीखने के लिए कोई अच्छे resources हैं क्या
आगे जो बनाना है उसमें Guile आजमाने की सोच रहा हूं, इसलिए यह पढ़ना रोचक लगा
WASM वाला काम भी अच्छा हुआ लगता है
https://wingolog.org/archives/2024/05/16/on-hoot-on-boot
हाल ही में Clojure से 3D boss fight prototype बनाया: https://prototype-game.pages.dev
पहले मुझे हर तरह का web development नापसंद था, लेकिन ClojureScript ने इसे सच में enjoyable बना दिया, और काश इसका इस्तेमाल और ज्यादा व्यापक होता
बाद में PC के सामने होने पर फिर कोशिश करूंगा
कौन-सी libraries इस्तेमाल कर रहे हैं, जानने की उत्सुकता है
बचपन में यह मेरे सबसे पसंदीदा games में से एक था
https://www.youtube.com/watch?v=dcJFldES9dg
टेबल में जोड़ने का अनुरोध तो किया था, लेकिन अब यह शायद पुरानी खबर हो सकती है
संदर्भ:
https://lispy-gopher-show.itch.io/logos-lisp-legend/devlog/7...
https://itch.io/post/10013482
https://ianthehenry.com/posts/janet-game/ होने के बावजूद Janet छूट गई है
लेख का copyright वर्ष 1899~1907 दिया है, लेकिन यह vintage जैसा नहीं दिखता—यह थोड़ी निराशा की बात है
scripting के लिए मैं फिर से Fennel पर लौट आया, क्योंकि बहुत सारी Lua libraries सीधे इस्तेमाल की जा सकती हैं और यह लगभग हर जगह, यहां तक कि iPad के a-Shell में भी बिना दिक्कत चलती है
इस thread में उपयोगी संदर्भ सामग्री थी और शायद बाद में फिर कोशिश कर सकता हूं: https://janet.zulipchat.com/#narrow/stream/409517-help/topic...
पहले से proven production path होने के बावजूद मैंने समय पर बस किसी तरह playable चीज़ बनाई, और “playable” कहना भी थोड़ा उदार ही है
बहुत उत्सुकता है कि Emacs Lisp से किस तरह का game बनाया गया
game programming के बारे में सोचते समय यह सबसे पहले दिमाग में आने वाला विकल्प नहीं है
Dunnet को मूल रूप से Ron Schnell ने 1982 में TOPS-20 पर चलने वाले Maclisp program के रूप में लिखा था
1992 में इसे Emacs Lisp में port किया गया, लेकिन यह सिर्फ porting से आगे गया—नए rooms, items और puzzles जोड़े गए, और MIT-केंद्रित content हटाया गया
उदाहरण के लिए, game के आखिरी हिस्से का “endgame” computer मूल रूप से MIT-SALLY नाम से MIT में था और Chaosnet के जरिए access होता था, लेकिन GNU Emacs version में ऐसे पुराने MIT references हटा दिए गए
इसके बजाय VAX 11/780 जैसी अधिक widely recognizable, लेकिन फिर भी अपने दौर का एहसास देने वाली चीजें जानबूझकर शामिल हैं
https://en.wikipedia.org/wiki/Dunnet_(video_game)
original यहां है: https://github.com/Quogic/DunnetPredecessor/blob/master/foo....
https://lcolonq.itch.io/slgj2024-game-boy-gizmo
https://asquared31415.itch.io/disassembly
https://grindingstone.itch.io/pendulum