2 पॉइंट द्वारा GN⁺ 2024-05-13 | 2 टिप्पणियां | WhatsApp पर शेयर करें
  • Lisp की होमोआइकॉनिसिटी वह गुण है जिसमें code और data को एक ही रूप में संभाला जाता है, और क्लासिक “Lisp in Lisp” को Python में लाने पर यह idea ज़्यादा परिचित syntax के भीतर सामने आता है
  • मूल Lisp में code representation M-expression और data representation S-expression दोनों थे, और “Lisp in Lisp” ने M-expression में S-expression Lisp को implement किया
  • Python version में S-expression को Python lists के रूप में दर्शाया गया है, और M-expression को function calls और conditionals में बदलकर अलग parser के बिना interpreter बनाया गया है
  • पहला interpreter atom, eq, car, cdr, cons, append जैसे list primitives पर आधारित है, और lambda support के लिए assoc, pairlis, और environment list जोड़े गए हैं
  • eval expression और environment को साथ में लेकर variable binding संभालता है, और pairlisassoc के जरिए dynamic scope तरीके से arguments और values को जोड़ता है

Lisp ने code और data का एकीकरण दिखाया

  • Lisp ने 1960 के दशक की शुरुआत में John McCarthy के Lisp paper और Lisp 1.5 manual के जरिए कई ऐसे ideas छोड़े जो दशकों बाद भी प्रासंगिक हैं
  • इनमें मुख्य है होमोआइकॉनिसिटी
    • सामान्य languages में code को data पर काम करने वाले operations की श्रृंखला के रूप में समझा जाता है
    • Lisp code और data को एक ही रूप में संभालता है, जिससे operator और operand की सीमा धुंधली हो जाती है
  • Alan Kay ने Lisp 1.5 manual के पेज 13 के निचले हिस्से में मौजूद “Lisp in Lisp” code को “Maxwell's Equations of Software” कहा था
    • इसमें यह उद्धरण शामिल है कि कुछ lines of code में पूरी programming दुनिया समाई हुई है, इसलिए यह एक बड़ा बोध था

“Lisp in Lisp” को Python में लाने का तरीका

  • लक्ष्य क्लासिक “Lisp in Lisp” code को Python में फिर से लिखते हुए original code की spirit को यथासंभव बनाए रखना है
  • Lisp में दो तरह के syntactic representations होते हैं
    • M-expression: code representation, meta का संक्षेप
    • S-expression: data representation, symbolic का संक्षेप
    • दोनों representations semantically equivalent हैं
  • मौजूदा “Lisp in Lisp” code M-expression में लिखा गया था और S-expression Lisp को implement करता है
  • Python implementation में Lisp S-expression को Python list के रूप में represent किया गया है
    • Lisp “List Processing” का संक्षेप है, और list नाम की एक data structure को केंद्र में रखकर काम करता है
    • Python list को Lisp S-expression को emulate करने के लिए उपयुक्त representation के रूप में इस्तेमाल किया गया है
  • M-expression को Python के function calls और conditionals जैसे code structures में translate किया गया है
    • इस mapping की वजह से string manipulation या अलग parser implement किए बिना interpreter बनाया जा सकता है

list primitives से बना पहला interpreter

  • Lisp implementation के लिए language के बाहर से उपलब्ध कुछ basic functions की जरूरत होती है
  • Python implementation में इस्तेमाल हुए list primitives ये हैं
    • atom(x): जाँचता है कि x list है या नहीं
    • eq(x,y): जाँचता है कि x और y समान हैं या नहीं
    • car(x): list का पहला element
    • cdr(x): list का बाकी हिस्सा
    • cons(x,y): atom को list से जोड़ता है
    • append(x,y): दो lists को जोड़ता है
  • कुछ recursive primitives को छोड़कर, Llama3-70b को Groq पर इस्तेमाल करके “Lisp in Lisp” code के subset को चलाने वाला interpreter जल्दी बनाया जा सका
  • उदाहरण में Python list S-expression की तरह काम करती है
  • पूरा code github gists पर उपलब्ध है

lambda और recursion के लिए विस्तार

  • पहली implementation में अहम feature lambda नहीं था
    • lambda Lisp में anonymous functions define और call करने का मुख्य तरीका है
    • Lisp में lambda न हो तो recursion implement नहीं किया जा सकता
    • recursion न हो तो हर computable चीज़ को compute कर पाने की न्यूनतम कसौटी, यानी Turing completeness, तक नहीं पहुँचा जा सकता
  • lambda जोड़ने के लिए assoc(x,y) और pairlis(x,y) जोड़े गए
    • assoc(x,y) list से implement किया गया key/value lookup है, और association list का इस्तेमाल करता है
    • pairlis(x,y) Python के zip(x,y) की तरह दो lists को जोड़े में बाँधता है
  • मूल Lisp में साधारण linear scan भी recursion से ही संभालना पड़ता था
    • क्योंकि मूल Lisp में loops नहीं थे
    • Python translation में assoc और pairlis को list comprehensions से अधिक संक्षेप में व्यक्त किया जा सकता है
  • COND processing में मूल Lisp के evcon को loop में translate किया गया है, और LAMBDA processing में भी evlis पर वही तरीका लागू किया गया है

environment list और dynamic scope

  • मूल Lisp का eval function दो arguments लेता है
    • पहला argument evaluate किया जाने वाला S-expression है
    • दूसरा argument key/value list के रूप में environment list है
  • environment LAMBDA processing में variable binding को बनाए रखता है
    • अगर function में x variable है और data assign किया जाता है, तो pairlis x symbol और data को pair करता है
    • paired value environment list में store या add की जाती है
    • जब x की जरूरत होती है, तो assoc उसे environment में खोजकर expression में फिर से substitute करता है
  • इस binding तरीके को dynamic scope कहा जाता है
  • अंतिम implementation मूल “Lisp in Lisp” को Python में लाने का रूप है, और आखिरी example में lambda execution तक शामिल है

2 टिप्पणियां

 
GN⁺ 2024-05-13
Hacker News की राय
  • अगर आपकी रुचि सरल और तेज़ Python-स्टाइल scripting Lisp में है, तो Clojure-स्टाइल भाषाओं Hy और Janet को देखना चाहिए

    1. Hy(https://hylang.org/): Python bytecode में compile होती है, आम तौर पर Python से धीमी है, लेकिन सभी Python libraries के साथ compatible है
    2. Janet(https://janet-lang.org/): Lua-स्टाइल का बहुत हल्का embedded virtual machine, लगभग 1MB, समान operations में Python से लगभग 2 गुना तेज़, और C interoperability बहुत आसान है
    • तेज़ Python-स्टाइल scripting के लिए, batteries-included Common Lisp https://github.com/ciel-lang/ciel भी है
      यह जल्दी शुरू करने के लिए binary के रूप में मिलता है, और रोज़मर्रा के कामों के लिए libraries भी शामिल हैं
      CL↔Python पक्ष के लिए https://github.com/CodyReichert/awesome-cl?tab=readme-ov-fil... भी देखने लायक है
    • Hy, Python से धीमी है? कम-से-कम runtime में तो ऐसा नहीं होना चाहिए
      मैं Hy maintainer हूँ, और अगर कोई meaningful performance difference दिखे, तो वह bug है
      1. Basilisp(https://github.com/basilisp-lang/basilisp): “Python 3.8+ को target करने वाली Clojure-compatible-ish Lisp dialect”
    • यह सनक जैसा लग सकता है, लेकिन Lisp मुझे हमेशा उसकी अनिवार्य enclosing parentheses की वजह से बहस को न्योता देने वाली भाषा जैसी लगी है
      M-expressions इस जाल से बचती हैं, इसलिए मैं सोचता हूँ कि क्या कभी कोई वास्तविक भाषा रही है जो Lisp की homoiconicity और conceptual elegance को बनाए रखते हुए ऐसी parentheses की मांग न करे
    • https://github.com/yaml/yamlscript
      यह ठीक वही है जो आप सोच रहे हैं। इसका विवरण भी बिल्कुल सीधा है: “Program in YAML”
      इसके बाद कहने को लगभग कुछ नहीं बचता
  • ज़रा ठहरिए, क्या यह बस Python में implement किया गया Lisp नहीं है?
    जैसा शीर्षक संकेत देता है, यह homoiconic Python तो नहीं लगता; क्या मैं कुछ मिस कर रहा हूँ?

    • Greenspun का दसवाँ नियम देखें तो, हाँ: https://en.m.wikipedia.org/wiki/Greenspun's_tenth_rule
    • मैं भी काफ़ी उत्साहित हो गया था कि यह homoiconic Python होगी, जिसे मैं अपने सहकर्मियों से Lisp अपनवाए बिना भी इस्तेमाल करा सकूँ, लेकिन नहीं, यह तो बस Lisp निकली
    • ऐसा ही लगता है। मैं भी इस homoiconic Python को देखने की जिज्ञासा से आया था, लेकिन यह संभव भी है या नहीं, पक्का नहीं कह सकता
      इसके लिए Python syntax को tuples, lists और dictionaries से बना होना चाहिए, और interpreter को उन्हें सीधे evaluate करना होगा
    • फ़र्क क्या है?
  • एक और functional language जिसे Python में संक्षेप में implement किया जा सकता है, वह है Binary Lambda Calculus
    कोड का बड़ा हिस्सा BLC के pure I/O model को संभालता है, और variable lookup के लिए associative list की जगह environment array को de Bruijn indices से index किया जाता है
    उसी पेज पर 9 अन्य language implementations भी हैं, और BLC का self-interpreter parser और tokenizer सहित 232 bits (29 bytes) में सबसे संक्षिप्त है
    [1] https://rosettacode.org/wiki/Universal_Lambda_Machine#Python

  • MIT के introductory programming course में सभी छात्रों से Python में Lisp interpreter लिखवाया जाता है
    यह उस दौर की एक निशानी है जब वह course सच में Lisp में पढ़ाया जाता था
    https://py.mit.edu/spring24

    • इसी तरह, मैंने विश्वविद्यालय में जो course लिया था, उसमें भी Lisp में एक बुनियादी Lisp interpreter implement करवाया गया था
  • मैंने कुछ मिलता-जुलता JS lists के साथ किया था: https://github.com/andrelaszlo/js-lisp

  • यह मज़ेदार भी है और विडंबनापूर्ण भी कि आधुनिक भाषाएँ कई दशकों बाद Lisp की शानदार खूबियों को फिर से खोज रही हैं
    कुछ दिन पहले मेरा एक Python प्रोग्राम, जो 9 घंटे से मेरे होम सर्वर API को कॉल कर रहा था, रुक गया और मैं बहुत खीझ गया। वह मिलते-जुलते API कॉल कर रहा था और predefined prompt templates तथा grammar constraints के साथ LLM को कॉल कर रहा था
    मैं बची हुई iterations को अलग से चलाने से पहले प्रोग्राम की state सेव करके उसे बंद करना चाहता था, लेकिन running Python code को modify करने या variables को inspect करने का कोई तरीका नहीं मिला, और आखिरकार 9 घंटे का काम खो दिया
    कुछ दिनों बाद मैंने https://malisper.me/debugging-lisp-part-1-recompilation/ देखा, और यह जानकर हैरानी हुई कि Common Lisp में ऐसी सुविधा दशकों पहले से भाषा में built-in थी। सबसे शक्तिशाली macro system जैसी दूसरी खूबियों के साथ भी यही बात है

    • यह हैरान करने वाली बात नहीं है कि आधुनिक भाषाएँ दशकों बाद Lisp की खूबियों को फिर से खोजती हैं। Lisp परिवार की भाषाएँ सबसे लचीली और अभिव्यक्तिपूर्ण भाषाओं में हैं
      लेकिन यही समस्या भी है। अभिव्यक्ति की शक्ति बहुत ज़्यादा है
      Lisp मुझे हमेशा mixed-media visual art की याद दिलाती है; अभिव्यक्ति की आज़ादी अच्छी लगती है, लेकिन आखिर में उसका परिणाम अक्सर अधिक पारंपरिक single-medium art की तुलना में कमतर होता है। इससे पता चलता है कि माध्यम की सीमाएँ भी अभिव्यक्तिशीलता जितनी ही महत्वपूर्ण हैं
    • state को कुछ हद तक inspect करने के लिए Py-spy या Pystack का इस्तेमाल किया जा सकता है
      या https://github.com/malor/cpython-lldb भी है
      और अधिक तरीकों के लिए https://github.com/albertz/pydbattach/
    • अगर कोई process कई घंटों तक चलती है, तो काम को disk पर सेव करना चाहिए और जहाँ रुक गया था वहाँ से फिर शुरू करने की तैयारी रखनी चाहिए
    • क्या कोई exception throw नहीं हुई थी?
  • यह implementation homoiconic Python कैसे है?

  • क्या ऐसा कोई Lisp है जिसमें type system हो, जो प्रोग्राम के बड़े होने पर Lisp के पढ़ने में कठिन हो जाने की प्रवृत्ति को कुछ हद तक नियंत्रित कर सके?
    अगर type system नहीं भी हो, तो क्या कोई और तत्व है जो इस प्रवृत्ति को संभाल सके, यह जानने की जिज्ञासा है
    metaprogramming सचमुच शानदार है, लेकिन कभी-कभी यह अब तक देखे गए सबसे कठिन abstract Haskell जैसा पढ़ाई देता है, बस उसमें राह दिखाने वाले type signatures भी नहीं होते
    मेरे हिसाब से type system और linter कोड को अपने-आप काबू में रखने के सबसे अच्छे औज़ार हैं, लेकिन Lisp चुनने की वजह को ही सीमित किए बिना Lisp projects की इस प्रवृत्ति को कैसे रोका जा सकता है, यह समझना मुश्किल है

    • type system वाले Lisp की बात करें तो Common Lisp याद आता है
      व्यवहार में standard के सबसे करीब SBCL compile-time type checking भी काफ़ी अच्छी देता है
      उदाहरण के लिए, (declare (type String a b)) के बाद अगर (+ a b) लिखें, तो यह warning दे देता है कि A का derived type STRING है जबकि उसे NUMBER होना चाहिए
      Scheme से CL में आने की मेरी सबसे बड़ी वजह यही type checking थी, और उसके बाद restarts तथा continuable asserts जैसी छोटी लेकिन उपयोगी सुविधाओं के कारण मैं वहीं बना रहा
    • दोस्ताना और आसानी से अपनाया जा सकने वाला विकल्प Typed Racket है, और शक्तिशाली लेकिन जटिल विकल्प Shen है
    • https://en.wikipedia.org/wiki/Dylan_(programming_language)
  • अगर expression-oriented Python होता, तो वह मौजूदा Python से कहीं बेहतर होता
    यह लेख शीर्षक से जो संकेत मिलता है, उसके बारे में नहीं है, लेकिन Lisp को समझाने के लिए अच्छा है

    • expression-oriented Python, Python ही नहीं होता
      फिर भी यह ठीक है, लेकिन “expressions को second-class syntax की तरह रखना” काफ़ी बुनियादी और जानबूझकर किया गया चुनाव है। यह इस तरह भी डिज़ाइन किया गया है कि जो developer parentheses soup लिखना चाहता है, उसके लिए काम आसान न हो
      इसलिए lambda: और := को जानबूझकर थोड़ा भद्दा रखा गया है ताकि उनका इस्तेमाल कम हो, और anonymous functions भी नहीं लिखे जा सकते
      Python ऐसी भाषा है जो कहती है कि अगर आपको कुछ चतुर करना है, तो callable object की बजाय iterator के रूप में करें
  • काश हर चीज़ में Lisp-शैली की बिना-व्याकरण वाली संरचना होती
    मेरे लिए वह बेहतर है, और शुक्र है कि CL में ऐसा करना आसान है

 
kayws426 2024-05-13

Python में एम्बेड किया गया Lisp का एक dialect
https://hylang.org/