2023 है, तो जाहिर है Common Lisp सीखते हैं
(log.schemescape.com)- भविष्य में भी इस्तेमाल किए जा सकने वाली भाषा पर सोचते हुए, इस बार का चुनाव व्यावहारिकता से ज़्यादा पुराना लेकिन आधुनिक development workflow को सीधे प्रयोग करके देखने के करीब था
- Janet, Lua जैसे क्षेत्र को लक्ष्य करने वाली एक छोटी Lisp/Clojure-परिवार की scripting language है, जिसने standard library और macro-आधारित metaprogramming की वजह से ध्यान खींचा
- Janet की portability, embedding capability, और Parsing Expression Grammars आकर्षक लगीं, लेकिन वे अभी की ज़रूरतों से सीमित रूप से ही मेल खाती थीं; CHICKEN Scheme, CLISP, SBCL, Packrat जैसे पुराने विकल्प भी काफ़ी पर्याप्त लगे
- Common Lisp का REPL-driven development इस बात के लिए खास है कि runtime error की स्थिति में stack, variables, और live data को देखा और बदला जा सकता है, फिर रुकी हुई execution को दोबारा शुरू किया जा सकता है
- नई भाषा और standard library सीखने की लागत है, लेकिन अगर यह workflow शुरुआत से ही design में शामिल हो, तो उसे सीधे अनुभव करना क़ीमती लगा
Janet से Common Lisp की ओर रुचि क्यों गई
- भविष्य में भी उपयोगी रहने वाला code लिखना चाहता था, इसलिए future-proof programming languages पर सोचता रहा, लेकिन कुछ बनाकर साझा करते समय आम तौर पर लोकप्रिय, portable, और सुविधाजनक भाषा चुनने वाला व्यावहारिक रवैया अपनाता हूँ
- दूसरी ओर, मज़े और प्रयोग के लिए दूसरी programming languages और tools भी देखता हूँ
- हाल ही में मुफ़्त किताब Janet for Mortals मिली, जिससे Janet में रुचि पैदा हुई
- Janet, Lua जैसी niche को लक्ष्य करने वाली अपेक्षाकृत छोटी Lisp/Clojure-प्रेरित scripting language है
- यह एक वास्तविक standard library, Lisp-शैली metaprogramming, और macros के ज़रिए compile-time execution देती है
- Janet में सामान्य Lisp-जैसेपन के अलावा जो चीज़ें सबसे ज़्यादा आकर्षक लगीं, वे थीं portability, embedding capability, और Parsing Expression Grammars
- फिलहाल किसी भाषा को embed करने की ज़रूरत नहीं है, इसलिए embedding capability निर्णायक कारण नहीं बनी
- portability के मामले में CHICKEN Scheme, CLISP, और Steel Bank Common Lisp भी अच्छे लगे
- parsing के लिए Packrat एक उचित विकल्प जैसा लगा
- आख़िरकार, Janet को मौजूदा Lisp विकल्पों के ऊपर चुनने की वजह कम होती गई
Common Lisp सीखने के पीछे REPL-driven workflow
- Common Lisp के लगभग अनोखे REPL-driven workflow पर लिखी गई पोस्ट सीखने की प्रेरणा बनी
- उदाहरण में
foofunction ऐसेbarfunction को call करता है जो अभी define नहीं हुआ, औरfooके चलने के दौरान error आता है- पुराने Lisp या Smalltalk environments में
fooका रुकना breakloop तक ले जाता है - breakloop, रुके हुए function के dynamic environment के भीतर एक पूरा REPL होता है
- रुके हुए call stack में ऊपर-नीचे जाकर हर stack frame में दिखने वाले variables देखे जा सकते हैं
- चल रहे program के live data की जाँच और उसमें बदलाव किया जा सकता है
- अगर कारण कोई ग़लत variable या field value हो, तो value बदलकर रुके हुए function को फिर से शुरू किया जा सकता है
- REPL के अंदर missing
barfunction define करकेfooको resume किया जा सकता है और एक उचित result पाया जा सकता है
- पुराने Lisp या Smalltalk environments में
- पहले भी कई “edit and continue” फीचर देखे थे, लेकिन Common Lisp को इस तरह के workflow को ध्यान में रखकर बनाया गया है, यह बात नई लगी
- अब तक का debugging अनुभव
printf debuggingसे आगे बढ़कर असली debugger इस्तेमाल करने तक पहुँचा हैprintf debuggingमें अस्थायी log code डाला जाता है, फिर दोबारा compile किया जाता है, और output देखकर समझा जाता है- जिन स्थितियों में program को बदलना या फिर से चलाना संभव नहीं होता, वहाँ debugger सीखना पड़ता है
- असली debugger सही tool है, लेकिन debugging environment सेट करना कष्टदायक या कभी-कभी असंभव भी हो सकता है
- Common Lisp, debugging को एक कदम और आगे ले जाने वाला environment लगा
- debugger में memory बदलकर संभावित fixes आज़माने का अनुभव पहले भी था
- लेकिन चल रहे process के भीतर code को फिर से लिखकर patch कर पाना खास तौर पर आकर्षक लगा
- Common Lisp सीखने का लक्ष्य यह देखना है कि program को इंटरैक्टिव तरीके से बनाना क्या वाकई काम करने का आनंददायक तरीका है
- सिर्फ़ नया workflow खोजने के लिए नई भाषा और standard library सीखना सबसे अच्छा विकल्प है या नहीं, यह पक्का नहीं है, लेकिन इससे बेहतर विकल्प भी साफ़ नहीं दिखता
- दूसरी भाषाओं में भी ऐसा REPL-editor integration हो सकता है
- लेकिन ऐसी सुविधाएँ अगर शुरुआत से समर्थित न होकर बाद में जोड़ी गई हों, तो उनमें bugs ज़्यादा हो सकते हैं
- अगर संतोष न भी मिले, तब भी इतना रहेगा कि इसे standard tools के साथ सबसे अच्छे हालात में आज़माया गया
- Common Lisp सीखने में मददगार सामग्री अलग पोस्ट Common Lisp resources में संकलित है
1 टिप्पणियां
Hacker News रायें
अब तक Common Lisp में मुझे जो चीज़ें अच्छी लगीं, उनमें condition system साफ-सुथरा है, और restart की मदद से दूर-दूर मौजूद code को भी आसानी से control किया जा सकता है। REPL-driven development भी तब बहुत सुविधाजनक है जब पता न हो कि आगे क्या होगा—जैसे किसी अपरिचित data source को parse करते समय—क्योंकि context खोए बिना code सुधारकर आगे बढ़ सकते हैं
implementations कई हैं और interoperability भी अच्छी है, इसलिए एक मामले में मैं speed के लिए SBCL और memory usage घटाने के लिए CLISP के बीच बदलकर इस्तेमाल कर पाया। Lisp सीखने में Scheme के बजाय CL की ओर झुकने की एक वजह यह भी थी कि compatible implementations कई हैं
Emacs में beginner होने के बावजूद Common Lisp integration शानदार लगा, और development के लिए इस्तेमाल होने वाले मेरे बेहद slow netbook पर भी ठीक चलता है। आजकल fast computers, VS Code और language servers के दौर में यह उतना बड़ा लाभ नहीं रहा, लेकिन इसमें पक्का retrofuture-सा feel है
कुछ कमियाँ भी हैं। सबसे लोकप्रिय package manager QuickLisp ठीक है, लेकिन modern language ecosystem में जिन features की आदत हो गई है, उस स्तर तक नहीं पहुँचता। भाषा खुद समय में स्थिर-सी हो गई है, इसलिए threads, synchronization, command-line arguments जैसी कई चीज़ों के लिए interoperability libraries चाहिए होती हैं। और अगर SBCL glibc के अलावा Linux distributions के लिए भी binaries distribute कर सके, इसके लिए fully static builds support करे, तो सच में बहुत अच्छा होगा
source code लाने जैसे महत्वपूर्ण काम के लिए अगर encryption या authentication support नहीं है, तो security की परवाह करने वालों के लिए QL विकल्प बनना मुश्किल है
साथ ही SBCL का SourceForge पर host होना भी समस्या है। SourceForge ने अतीत में download archives में malware inject किया था, इसलिए मैं इसे भी security issue मानता हूँ। आज SourceForge इस्तेमाल करते रहने की कोई ठोस वजह दिखती नहीं, और समझ नहीं आता कि कोई महत्वपूर्ण project अब भी वहाँ क्यों है
Lisp, खासकर Common Lisp, मुझे सच में बहुत पसंद है, लेकिन ऐसी चीज़ों की वजह से मैं दूर हो गया, और इन्हें ठीक करने में खास रुचि भी नहीं दिखती
https://www.timmons.dev/posts/static-executables-with-sbcl.h...
https://www.timmons.dev/posts/static-executables-with-sbcl-v...
https://cons.io
Gerbil/Gambit Scheme, CL के विकल्प के रूप में, fully static binaries बना सकता है
इसे सामान्य Quicklisp library के रूप में, तुरंत शुरू होने वाली core image के रूप में, और binary के रूप में भी इस्तेमाल किया जा सकता है। Scripts भी लगभग तुरंत चल सकती हैं, इसलिए इसमें Babashka जैसी कुछ समानता है। अभी details polish कर रहा हूँ और यह v1.0 नहीं है
blog में “runtime error को restart किए बिना टूटे code को उसी जगह ठीक करके handle करना” यहाँ दिखाया जाना चाहिए था: https://www.youtube.com/watch?v=jBBS4FeY7XM
अगर लंबी और भारी computation चलाते हुए आखिरी चरण में error आ जाए, तो शुरुआत से फिर चलाने के बजाय interactive debugger में जाते हैं, error वाली line पर जाते हैं, सुधारे हुए function को compile करते हैं, फिर debugger में लौटकर stack frame के एक point से execution resume करते हैं। उसके बाद program को pass होते देख सकते हैं
M-से उसे REPL में copy करने का तरीका मुझे Clojure केtap>से कहीं बेहतर लगता है। Portal जैसे tools इस्तेमाल करने पर भीtap>मुझे सजाए-संवारे pretty-printing जैसा ही लगता हैperformance के मामले में भी Common Lisp में static type declarations दे सकते हैं, और SBCL ऐसा करने पर बहुत efficient code generate कर सकता है। अपने लिखे code पर
DISASSEMBLEचलाकर असल में क्या emit हो रहा है देखना और optimize करना मददगार होता है। खासकर SB-SIMD और Loopus जैसे packages numerical computing applications में सचमुच बहुत मदद करते हैं:quackkey true है तो इसे duck की तरह treat करो” वाला तरीका entity-component-system-style game design के लिए अच्छी तरह fit बैठता हैलेकिन Common Lisp का development style, और दुनिया में condition system, पिछले एक साल में मुझे सच में बहुत याद आए। मैं CL में कोई बहुत proficient hacker भी नहीं हूँ, फिर भी यह जल्दी ही आदत में आ गया। काश CLOS और CL के primitive data types, जितना दिखते हैं उससे बेहतर तालमेल रखते
Cider में यह निश्चित रूप से आसानी से किया जा सकता है, और दूसरे editors के main tools भी शायद इसी तरह काफी अच्छा कर लेते होंगे
DISASSEMBLEजैसा काम कुछ हद तक किया जा सकता हैhttps://github.com/Bronsa/tools.decompiler जैसे सहायक प्रोजेक्ट हैं, और OpenJDK का JitWatch (https://github.com/AdoptOpenJDK/jitwatch) भी है। दूसरे JVMs में भी मिलते-जुलते tools हैं
Lisp जितना सहज तो नहीं, लेकिन फिर भी संभव है
कोई ऐसा obscure लेकिन आकर्षक ढंग से चलने वाला सिस्टम बना लेना अच्छी बात है, लेकिन अब जिन लोगों की salary को zeroes की संख्या से बताया जा सकता है, उनके अलावा कोई भी उसे छूना नहीं चाहेगा
https://www.digitalocean.com/community/tutorials/java-repl-j...
https://github.com/waf/CSharpRepl
https://pub.dev/packages/interactive
Ruby, Python, PHP, Lua की तो बात ही छोड़िए, C++ में भी एक अधकचरा-सा REPL है: https://github.com/root-project/cling
जब भी मैं कहता हूं कि Lisp में REPL अब differentiator नहीं रहा, मुझे downvote मिलते हैं
https://github.com/kaveh808/kons-9
हालांकि इस तरह की redefinition और overwriting आखिरकार namespace को contaminate कर देती है, और किसी point पर कुछ टूट जाता है और server reload करना पड़ता है
इसकी कमियां भी बहुत हैं, लेकिन वे लगभग हर दूसरी language और development environment की pure technical कमियों से बदतर नहीं हैं। Python और JS ज्यादा widely used हैं और libraries भी ज्यादा हैं, लेकिन development experience मुझे कहीं ज्यादा खराब लगता है। C#, TS, Py, Hs और और भी obscure languages कई वर्षों तक काफी इस्तेमाल की हैं, लेकिन जब भी मैं उन languages में फंसता हूं या साफ तौर पर खराब चीजों से सचमुच चिढ़ जाता हूं, तो CL(SBCL + Emacs + Slime) पर लौट आता हूं। तब सुकून मिलता है और भरोसा होता है कि दुनिया में अभी भी कुछ अच्छा मौजूद है
अभी हम एक product के लिए funding raise कर रहे हैं जिसे हमने मूर्खतापूर्वक TypeScript में bootstrap किया था, लेकिन launch version CL में दोबारा बनाएंगे। इसका मतलब है कि launch से पहले अगले 3–5 साल CL में, CL के अंदर काम करूंगा, और DSL implementation, code generation, macro work, static type interpreter implementation जैसी मजेदार चीजें कर पाऊंगा
C# में काम करते समय Lisp की कौन-सी चीजें याद आती हैं?
मेरा थोड़ा कट्टर विचार है कि functional programming व्यापक रूप से popular इसलिए नहीं हुई क्योंकि programs लिखने के लिए यह निश्चित रूप से ठीक है, लेकिन आजकल ज्यादातर software “मेरे PC/server पर command line से चलकर खत्म होने तक चलने वाला program” नहीं है, बल्कि “start होकर user input पर react करता है और user के बंद करने पर बंद होता है” या “start होने के बाद network या दूसरे automated I/O पर respond करता है और जब कोई दूसरा software उसे रुकने को कहे तो रुकता है”
ऐसी चीजें pure functional style में करना कहीं ज्यादा कठिन है, या कम से कम strong-opinionated functional implementations में, जिन्हें मैंने इस्तेमाल किया है, ऐसा ही था। क्योंकि अब यह सिर्फ कोई expression evaluate करना नहीं रह गया; state initialize करनी होती है, I/O पर react करना होता है, state update करनी होती है या extra I/O करना होता है, और monitoring, receiving, additional I/O व state updates के लिए parallelization तक इस्तेमाल करनी पड़ सकती है
बेशक Lisp में ये चीजें करना असंभव नहीं है, लेकिन undergraduate के समय कुछ semesters की functional programming और C++/Scala में professionally functional features इस्तेमाल करके ऐसे problems हल करने के अनुभव के आधार पर, ऐसे applications में functional programming को अच्छी तरह चलाना काफी मुश्किल लगा, और यही mismatch मुझे functional programming में और गहराई तक जाने से हिचकाता है
Common Lisp से अलग, कई बार ऐसा हुआ कि मुझे ऐसा code लिखना पड़ा जो code generate करता हो। इस क्षेत्र में Lisp चमकता हुआ लगेगा, लेकिन अभी तक आज़माने का मौका नहीं मिला। Common Lisp के बारे में सोचने से पहले किए गए हाल के project examples में static site generator में किसी खास JSON Schema को validate करने वाला code generate करना, और programming game के story content में इस्तेमाल के लिए Markdown से JSX generate करना शामिल है
अब तक इस्तेमाल किए गए अनगिनत C macros की तो बात ही छोड़िए
दूसरे styles की अच्छी features को भी पूरी तरह छोड़ने की ज़रूरत नहीं है। functional programming के कुछ हिस्से सामान्य languages में भी धीरे-धीरे अधिक आम हो रहे हैं। उदाहरण के लिए Rust भी कई मामलों में functional patterns का इस्तेमाल करता है
और Lisp को चाहें तो object-oriented या imperative style में भी इस्तेमाल किया जा सकता है। यह Haskell नहीं है
Lisp शुरुआत का बिंदु है और Haskell असली चीज़ है, ऐसा मानता हूँ। भले ही actual production code न लिखें, उस style को सीखने की सलाह दूँगा
(let ((pair (cons 1 nil)))(setf (cdr pair) pair)(list (first pair) (second pair) (third pair)));; => (1 1 1)अगर “हमेशा के लिए compile होगा” चाहिए, तो ANSI C में लिखें
अगर “हमेशा ज़िंदा रहेगा” चाहिए, तो Python 2.7 में लिखें और उसे पूरी organization के infrastructure templates की रीढ़ बना दें। custom Ansible module हो तो bonus points
मेरी उम्मीद यह है कि Lisp miscellaneous चीज़ों और boilerplate को minimize या abstract करके विचारों को code में express करना आसान बना दे। मुझे Lisp expressions विचार व्यक्त करने का सबसे natural तरीका लगते हैं
मेरी मुख्य रुचि GUI apps लिखने में है, इसलिए Clog सीखना या किसी GUI toolkit के ऊपर अच्छा wrapper ढूँढना या develop करना चाहता हूँ
(do-it (do-it first))(do-it first)ठीक काम करता है, लेकिन अगर(do-it (do-it first))call fail हो जाए तो क्या होता है?अगर broken point पर control मिल जाए और
do-itdefinition को ठीक कर सकें, तो अच्छा होगा। लेकिन ठीक करने पर(do-it first)का result भी बदल जाता हैतब machine जिस current point पर है, वह current code से अब पहुँचने योग्य point नहीं रह जाता
अगर ऐसा fix किया जिससे आगे बढ़ना संभव हो गया, लेकिन उसी fix के कारण वह state ही बदल जाए जिसमें fix करने के लिए control मिला था, तो यह कैसे काम करता है, मुझे सच में समझ नहीं आता