1 पॉइंट द्वारा GN⁺ 2024-10-18 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • Douglas Hofstadter का 1983 का लेख AI शोध में व्यापक रूप से इस्तेमाल होने वाली Lisp को एक छोटे mathematical kernel पर बनी हुई सुरुचिपूर्ण और लचीली भाषा के रूप में परिचित कराता है
  • Lisp की interactivity read-eval-print loop में दिखती है, जहाँ उपयोगकर्ता expression दर्ज करता है, interpreter उसे पढ़ता है, evaluate करता है, print करता है, और फिर अगले input का इंतज़ार करता है
  • Lisp objects मुख्यतः atom और list से बनते हैं, और nil एक अपवादस्वरूप स्थिति रखता है क्योंकि वह empty list भी है और atom भी
  • quote, eval, car, cdr, cons, setq, set, lambda, def, cond code और data को एक ही list structure में संभालने देते हैं, जिससे नए functions को धीरे-धीरे बनाया जा सकता है
  • function composition, conditional expressions, side effects और applicative style, तथा recursive thinking उदाहरणों के साथ जुड़े हैं, और अंत का power function तथा “porpuquine” रूपक Lisp-शैली recursion की ओर संकेत करते हैं

AI शोध और Lisp की भूमिका

  • 1983 के समय AI एक ऐसा शोध क्षेत्र था जो flexibility, common sense, insight, creativity, self-awareness, और humor जैसे व्यवहारों को computers में लागू करने की कोशिश कर रहा था
  • अमेरिका में लगभग 2,000 लोग AI में पेशेवर रूप से जुड़े थे, और विदेशों में भी लगभग इसी पैमाने के शोधकर्ता थे
  • AI शोधकर्ता AI तक पहुँचने के सर्वोत्तम रास्ते पर काफ़ी बँटे हुए थे, लेकिन programming language के चयन में वे लगभग समान रूप से Lisp का उपयोग करते थे
  • Lisp नाम “list processing” से आया है, और यह कोई पूर्ण acronym नहीं है
  • Lisp का आकर्षण इस बात में है कि यह एक “crisp” और “elegant” भाषा है
    • जहाँ कई भाषाएँ बहुत-सी मनमानी सुविधाएँ समेटे रहती हैं, वहीं Lisp और Algol जैसी कुछ भाषाएँ गणित की किसी शाखा की तरह एक स्वाभाविक kernel के इर्द-गिर्द बनी होती हैं
    • Lisp के kernel में “crystalline purity” है, और यह purity सिर्फ़ aesthetic sense ही नहीं बल्कि flexibility में भी योगदान देती है

Mathematical logic से list processing language तक

  • Lisp की गहरी जड़ें mathematical logic में हैं
    • 1920–1930 के दशक में Thoralf Skolem, Kurt Godel, और Alonzo Church ने logic में जो विचार दिए, वे बाद में Lisp में शामिल हुए
  • वास्तविक computer programming की शुरुआत 1940 के दशक में हुई, और Lisp जैसी high-level languages 1950 के दशक में सामने आईं
  • पहली list processing language Lisp नहीं बल्कि IPL (Information Processing Language) थी
    • IPL को 1950 के दशक के मध्य में Herbert Simon, Allen Newell, और J. C. Shaw ने विकसित किया था
  • John McCarthy ने 1956–1958 के बीच पहले से मौजूद विचारों के आधार पर Lisp नाम की algebraic list processing language बनाई
    • Lisp जल्दी ही MIT Artificial Intelligence Project के आसपास के युवा शोधकर्ताओं में फैल गई
    • इसे IBM 704 पर implement किया गया और फिर दूसरे AI groups तक पहुँची
    • इसके कई dialects बने, लेकिन उनका elegant central kernel साझा रहा

Interactive Lisp और REPL

  • कई दूसरी high-level languages के विपरीत, Lisp को interactive language के रूप में प्रस्तुत किया गया
  • उपयोगकर्ता terminal पर Lisp चलाता है, prompt देखता है, और expression दर्ज करता है
    • उदाहरण: (plus 2 2) दर्ज करने पर 4 print होता है और नया prompt दिखाई देता है
  • Lisp interpreter की मुख्य कार्यप्रणाली read-eval-print loop है
    • expression पढ़ना
    • expression को evaluate करना
    • उपयुक्त value print करना
    • यह संकेत देना कि अगला expression पढ़ने के लिए तैयार है
  • इस संरचना की वजह से उपयोगकर्ता एक-एक करके अपनी “इच्छाएँ” दर्ज कर सकता है और तुरंत परिणाम देख सकता है
  • कई non-interactive languages में पहले पूरा program लिखना और फिर उसे चलाना पड़ता है, इसलिए कई चरणों का पूरी तरह मेल खाना ज़रूरी होता है और errors ठीक करना भी अप्रत्यक्ष तथा महँगा हो सकता है
  • Lisp एक समय में एक expression चलाने के तरीके से incremental development और debugging को संभव बनाती है

Polish notation और parentheses

  • Lisp के arithmetic expressions में Polish notation का उपयोग होता है, जिसमें operator operands से पहले आता है
    • उदाहरण: (times (plus 6 3) (difference 6 3)) का मूल्य 27 होता है
  • यह notation Polish logician Jan Lukasiewicz ने computers के आने से पहले बनाई थी
  • Lisp expressions में parentheses बहुत दिखाई देते हैं
    • लंबे expressions का कई closing parentheses के साथ समाप्त होना भी आम बात है
    • शुरू में यह भारी लग सकता है, लेकिन आदत पड़ने पर logical structure सहज रूप से दिखने लगता है
  • उदाहरणों को structure स्पष्ट करने वाली indentation के साथ pretty printing रूप में दिखाया गया है

atom, list, nil

  • Lisp का केंद्र manipulable structure है, और सारे programs structures को बनाने, बदलने और नष्ट करने के तरीके से काम करते हैं
  • structure दो प्रकार के होते हैं
    • atom: मूल object जिसे आगे विभाजित नहीं किया जा सकता
    • list: एक निश्चित क्रम में रखे गए कई elements की संरचना
  • हर Lisp object या तो atom होता है या list, और केवल एक अपवाद nil है
    • nil एक atom भी है और list भी
    • nil empty list को दर्शाता है
    • () और nil का अर्थ एक ही है, लेकिन nil अधिक प्रचलित है
  • list के elements atom भी हो सकते हैं और list भी
    • उदाहरण: (zonk blee strill (croak flonk)) चार elements वाली list है, और इसका अंतिम element स्वयं दो elements वाली list है
  • Lisp sentence स्वयं भी list होती है
    • (plus 2 2) भी एक list है
    • Lisp interpreter lists और atoms को manipulate करके नए “commands” बना और evaluate कर सकता है

value, quote, eval

  • atoms के पास values हो सकती हैं
    • numeric atoms की स्थायी value वही स्वयं होती है
    • nil की value nil है
    • t भी एक विशेष atom है जिसकी स्थायी value वही स्वयं है
  • setq atom को value assign करता है
    • (setq pie 4) से pie की value 4 हो जाती है
    • (setq pie (plus 2 2)) से भी pie की value 4 हो जाती है
  • atom की value सिर्फ़ संख्या नहीं, कोई भी Lisp object हो सकती है
    • atom भी और list भी
  • quote evaluation को रोकता है और list या atom को ज्यों का त्यों data की तरह मानने देता है
    • (setq pie (plus 2 2)) अंदर के expression को evaluate करके pie में 4 store करता है
    • (setq pi '(plus 2 2)) list (plus 2 2) को स्वयं pi में store करता है
  • eval value के रूप में store किए गए expression को फिर evaluate करता है
    • यदि pi की value (plus 2 2) है, तो (eval pi) 4 लौटाता है
    • interpreter आम तौर पर केवल एक चरण evaluate करता है, लेकिन eval से अतिरिक्त evaluation माँगी जा सकती है

car, cdr, cons

  • nil को छोड़कर हर list में कम-से-कम एक element होता है, और पहले element को car कहा जाता है
    • (eval pi) का car eval है
    • (plus 2 2) का car plus है
  • car का function name होना आवश्यक नहीं है
    • ((1)(2 2) (3 3 3)) का car (1) है
  • car को हटाने पर जो list बचती है, वह cdr है
    • (a b c d) का cdr (b c d) है
    • फिर क्रमशः (c d), (d), और nil तक पहुँचा जा सकता है
  • nil का न तो car होता है न cdr, और उस पर car या cdr लेने की कोशिश error देनी चाहिए
  • cons किसी मौजूदा list के आगे नया car जोड़कर नई list बनाता है
    • यदि x का मान (cake cookie) है, तो (cons 'pie x) से (pie cake cookie) बनता है
    • इस दौरान मौजूदा x नहीं बदलता
  • quote हो या न हो, इससे परिणाम बदलता है
    • यदि pie की value 4 है, तो (cons pie x) (4 cake cookie) लौटाएगा
    • (cons 'pie x) atom name pie को स्वयं आगे जोड़ देगा

setq और set का अंतर

  • Lisp interpreter हमेशा arguments को evaluate नहीं करता, और setq इसका प्रमुख अपवाद है
  • setq का पहला argument evaluate नहीं होता, बल्कि सीधे variable name माना जाता है
    • setq में q का मतलब quote है, यानी पहला argument quoted की तरह treat होता है
  • set setq जैसा है, लेकिन उसका पहला argument भी evaluate होता है
    • यदि x की value k है, तो (set x 7) x को नहीं बदलता बल्कि k की value 7 कर देता है
  • उदाहरण के लिए यह क्रम दिया गया है
    • (setq a 'b)
    • (setq b 'c)
    • (setq c 'a)
    • (set a c)
    • (set c b)
  • इसे चलाने के बाद a, b, और c तीनों की values a हो जाती हैं
  • set आम तौर पर ज़्यादा इस्तेमाल नहीं होता, और इस तरह की उलझन भी बहुत सामान्य नहीं है

function definition और lambda

  • programming की बड़ी शक्ति इस क्षमता में है कि मौजूदा operations से नए compound operations परिभाषित किए जाएँ और फिर इस प्रक्रिया को दोहराकर अधिक जटिल operations का repertoire तैयार किया जाए
  • Lisp में नए functions पहले से ज्ञात functions के माध्यम से define किए जाते हैं
  • rac ऐसा example function है जो list का आख़िरी element लौटाता है
    • आख़िरी element पाने के लिए list को reverse करके car लिया जा सकता है
    • परिभाषा: (def rac (lambda (lyst) (car (reverse lyst))))
  • lambda के बाद आने वाला (lyst) function का parameter, यानी dummy variable, दर्शाता है
  • def से define करने के बाद rac ऐसा function बन जाता है जिसे car की तरह इस्तेमाल किया जा सकता है
    • (rac '(your brains)) brains लौटाता है
  • readers-digest-condensed-version नाम का function लंबी list से सिर्फ़ पहला और आख़िरी element लेकर एक छोटी list बनाता है
    • यदि James Joyce की Finnegans Wake को शब्दों की list माना जाए, तो इसका परिणाम (riverrun the) होगा
  • rejoyce नाम का उलटा operation एक कल्पित function है जो दो शब्दों से शुरू और अंत तय होने वाला उपन्यास बना दे, और इसे पाठक के अभ्यास के लिए छोड़ा गया है

return values, side effects, applicative style

  • कुछ लोग मानते हैं कि Lisp और संबंधित languages में दो लक्ष्य वांछनीय और संभव हैं
    • हर sentence एक value लौटाए
    • sentence का प्रभाव केवल उसकी return value के माध्यम से हो
  • लेख में चर्चा की गई Lisp dialects पहला लक्ष्य पूरा करती हैं, लेकिन दूसरा लक्ष्य अनिवार्य रूप से नहीं
  • (reverse x) स्वयं x को नहीं बदलता, बल्कि x जैसी लेकिन उल्टे क्रम वाली नई list बनाकर लौटाता है
    • ठीक वैसे ही जैसे (plus 2 2) संख्या 2 की value नहीं बदलता
  • cons भी मौजूदा list को बदले बिना नई list लौटाता है
  • दूसरी ओर, setq ऐसा command है जो variable binding बदलने जैसा side effect छोड़ता है
    • side effects में variable binding बदलने के अलावा input/output भी शामिल हो सकते हैं
  • applicative programming के समर्थक केवल उसी शैली को पसंद करते हैं जिसमें functions बिना side effects के values की गणना करके आगे बढ़ाएँ
  • इस शैली में स्वीकार्य binding केवल function call के दौरान अस्थायी रूप से बनने वाली lambda binding है
    • function की computation समाप्त होते ही dummy variable की binding समाप्त हो जाती है
  • लेख का वक्ता applicative style को elegant मानता है, लेकिन बड़े AI-शैली programs बनाने में उसे व्यावहारिक नहीं समझता
  • सख़्त applicative programming में def भी एक चरम उदाहरण बन जाता है, क्योंकि वह permanent function definition को memory में store करता है, इसलिए उसे भी स्वीकार नहीं किया जाएगा

conditional expression cond और निर्णय

  • Lisp को अधिक रोचक काम करने हों, तो उसे मध्यवर्ती प्रक्रिया में होने वाली घटनाओं के अनुसार निर्णय लेने आना चाहिए, और इसके लिए conditional expressions ज़रूरी हैं
  • उदाहरण: (cond ((eq x 1) 'land) ((eq x 2) 'sea))
    • यदि x, 1 है तो land
    • यदि x, 2 है तो sea
    • अन्यथा nil लौटता है
  • eq Lisp का function है जो दोनों arguments की values समान होने पर t और अलग होने पर nil लौटाता है
  • cond sentence cond नाम से शुरू होता है और उसमें कई clauses होते हैं
    • हर clause condition और result से बनी 2-element list होती है
    • conditions को क्रम से जाँचा जाता है, और जो पहली condition nil के अलावा कोई value लौटाए, उसका result evaluate होकर पूरे cond की value बन जाता है
    • उसके बाद के clauses नहीं जाँचे जाते
  • अंत में condition के रूप में t वाला catch-all clause जोड़ देने पर nil की जगह default result लौटाया जा सकता है
    • उदाहरण में ऐसा cond दिया गया है जो land और sea दोनों असफल होने पर air लौटाता है

power और recursive structure

  • लेख के अंत में स्पष्ट pattern वाले function definitions आते हैं
    • square = k * k
    • cube = k * square(k)
    • 4th-power = k * cube(k)
    • और यही क्रम आगे चलता है
  • सवाल उठाया गया है कि क्या इस पूरे pattern को एक साथ समेटने वाला दो-parameter function power define किया जा सकता है
    • (power 9 3) को 729 लौटाना चाहिए
    • (power 7 4) को 2,401 लौटाना चाहिए
  • इसके लिए ज़रूरी सारे tools मुख्य लेख में पहले ही दिए जा चुके हैं, और अब पाठक की सूझ-बूझ की परीक्षा है
  • अंत की Glazunkian porpuquine कहानी recursive structure को एक रूपक की तरह पेश करती है
    • porpuquine के काँटे स्वयं छोटे porpuquine हैं
    • Outer Glazunkia में हमेशा 9 काँटे होते हैं, और Inner Glazunkia में हमेशा 7 काँटे
    • 0-inch porpuquine के पास कोई काँटा नहीं होता, इसलिए infinite regress वहीं रुक जाता है
  • इस जीव की “buying power” या “power” उसके भीतर शामिल छोटे 0-inch porpuquine noses की संख्या से जुड़ती है, और इसी रूपक के साथ पहले वाले power प्रश्न पर लेख समाप्त होता है

मूल पुनर्प्रकाशन का संदर्भ

  • Gist की शुरुआत बताती है कि यह लेख 1980 के दशक के मध्य की Scientific American की पुरानी प्रतियों में मिला Douglas Hofstadter का Lisp परिचय है
  • examples अब भी Emacs में कुछ aliases सेट करके चलाए जा सकते हैं
    • plus+
    • quotient/
    • times*
    • difference-
  • अंत में कहा गया है कि यदि आपको Hofstadter की यह अनोखी Lisp-मार्गदर्शिका पसंद आई हो, तो उनकी किताब Metamagical Themas में इसी तरह के और लेख मिल सकते हैं

1 टिप्पणियां

 
GN⁺ 2024-10-18
Hacker News टिप्पणियाँ
  • उदाहरण में "oval" और "snot" फ़ंक्शन नामों से मैं उलझ गया था, लेकिन कुछ सेकंड बाद समझ आया कि ये क्रमशः "eval" और "snoc" की टाइपो हैं
    असली कोड को (cond ((eq (eval pi) pie) (eval (snoc pie pi))) (t (eval (snoc (rac pi) pi)))) की तरह पढ़ा जाना चाहिए
    https://www.jstor.org/stable/24968822 से मूल Scientific American लेख डाउनलोड करके जाँचा, और सचमुच oval/snot दरअसल eval/snoc की टाइपो निकले

    • सुधार पर भी सुधार: "oval" और "snot" सच में "eval" और "snoc" की टाइपो हैं
      और snoc, उल्टा लिखा cons लगता है, जबकि rac, उल्टा लिखा car
    • यह OCR त्रुटि भी हो सकती है
  • यह लेख फिर दिखाता है कि Lisp की लोकप्रियता सीमित रहने का एक बड़ा कारण Lisp को समझाने का तरीका था
    ऐसे Lisp लेखों ने बचपन में मुझे कुछ भी ऐसा नहीं सिखाया जिसे मैं सच में काम में ला सकूँ, और न ही यह दिखाया कि assembly/C/Pascal वगैरह के मुकाबले कोई काम X कितना आसान हो जाता है
    आज मैं होता तो यह दिखाता: “assembly में 7 महीने लेने वाला स्पेल-चेकर? बैंक-switched memory वाले microcomputer पर Lisp में यह लगभग मामूली काम है, और garbage collection भी कमजोर CPU पर निर्णायक साबित हो सकता है”
    अनगिनत Lisp लेख और पाठ्यपुस्तकें सिर्फ lists, recursion और AI की बातें दोहराती रहीं, लेकिन उपयोगी काम करना नहीं दिखाया, इसलिए लगता है जैसे मैंने चिमटी, चावल के दाने और गोंद से प्रोग्रामिंग सीखने में अपना समय बर्बाद किया

    • Common Lisp: A Gentle Introduction to Symbolic Computation इस संदर्भ में उपयोगी हो सकती है: https://www.cs.cmu.edu/~dst/LispBook/
    • Practical Common Lisp भी है: https://gigamonkeys.com/book/
    • Hofstadter के बाद के लेखों में और भी दिलचस्प उदाहरण थे
      बचपन में मैंने Byte मैगज़ीन में पहली बार symbolic differentiation और algebraic simplification को Lisp में लिखे कोड के रूप में देखा था; उसका पीछा करना मुश्किल था, लेकिन उसमें कुछ आकर्षक ज़रूर था
      Basic में वह आसान होता, ऐसा नहीं लगता; बाद में समझ आया कि वह कोड बहुत शानदार भी नहीं था, लेकिन 80 के दशक के आख़िर में PC पर XLisp और SICP मिलने के बाद ही मैं सच में Lisp का मुरीद बना
  • मुझे Hofstadter की लेखन शैली बहुत पसंद है। उन्होंने Lisp को खोजते समय की भावना को बहुत अच्छी तरह पकड़ा है
    मैं 80 के दशक में प्रोग्रामिंग सीखने वाला एक बच्चा था, और हाई स्कूल व कॉलेज के शुरुआती दिनों तक BASIC, Fortran, Pascal, COBOL थोड़ा-बहुत कर चुका था; उनमें फ़र्क थे, लेकिन बुनियादी तौर पर वे एक जैसे ही लगते थे
    फिर UC Berkeley की पहली computer science क्लास Lisp की एक बोली Scheme में हुई, और वह पूरी तरह झकझोर देने वाला अनुभव था
    Hofstadter की तरह मुझे भी वह गणित के सबसे क़रीब लगी, उसने गणित के सिद्धांत वाले कोर्सों की बहुत याद दिलाई, और वह पहली भाषा थी जो मुझे सच में सुंदर लगी
    यह उद्धरण मुझे ख़ास तौर पर पसंद आया: “Lisp और Algol गणित की किसी शाखा की तरह एक स्वाभाविक कोर के आसपास बनाए गए थे। Lisp के केंद्र में एक स्फटिक जैसी शुद्धता है, जो सिर्फ़ सौंदर्यबोध को आकर्षित नहीं करती, बल्कि उसे अधिकांश भाषाओं से कहीं अधिक लचीला भी बनाती है”

    • क्या आपने Haskell इस्तेमाल किया है? मेरे लिए वह प्रक्रियाओं के बजाय परिभाषाओं से बनी हुई लगती है, इसलिए गणित के और भी ज़्यादा क़रीब महसूस होती है, और दिखने में भी गणित जैसी लगती है
    • मूल लेख से थोड़ा हटने का जोखिम है, लेकिन मुझे लगता है कि इसे “गणित” कहना उल्टा बात को धुंधला कर सकता है
      एक ऐसे व्यक्ति के नज़रिए से भी जो algebraic topology का शोधकर्ता बनना चाहता था, Scheme दरअसल उस प्रोग्रामिंग शैली की सुघड़ और न्यूनतम अभिव्यक्ति के अधिक क़रीब है जो dynamic typing और garbage collection वाली भाषाओं में व्यापक है
      यह इस अर्थ में “theory” जैसा लगता है कि यह बहुत पूर्ण दिखता है, और Scheme में समस्या-समाधान का तरीका सोच लेने के बाद आप उसे दूसरी dynamic typed भाषाओं में भी ले जाकर सुरुचिपूर्ण हल तक पहुँच सकते हैं
      Scheme उस दौर के पारंपरिक Lisp की तुलना में lexical scope, functions और variables के लिए एकल namespace जैसी बातों में अधिक सरल और व्यवस्थित भाषा थी
  • 1983 तक इस क्षेत्र की शुरुआत को लगभग 20 साल हो चुके थे, फिर भी इसमें ऐसे AI की बात हो रही है जो “लचीलापन, सामान्य समझ, अंतर्दृष्टि, रचनात्मकता, आत्म-जागरूकता, हास्य” रखे
    मज़ेदार बात यह है कि यह सूची उन चीज़ों की सूची जैसी लगती है जिनमें LLM वास्तव में कमज़ोर हैं
    फिर भी कम से कम उस दिशा में शून्य से अधिक प्रगति तो हुई है

    • जिन सामान्य लोगों से मैं मिलता हूँ, उनकी तुलना में LLM ने सामान्य समझ, अंतर्दृष्टि, रचनात्मकता, आत्म-जागरूकता, हास्य में औसत इंसान जितना तो दिखाया ही है
      शायद उससे भी ज़्यादा दिखाया है, लेकिन ऐसा कहने पर मुझे ख़ुद भी थोड़ा अजीब लगता है
    • Hofstadter के शोध समूह का ऐसे सवालों से निपटने का लंबा इतिहास रहा है
      भले ही बहुत सी चीज़ें अब तक ठोस नतीजों में नहीं बदलीं, फिर भी उन्हें पढ़ना दिलचस्प है
  • इस लेख के साथ जिन दो साथी लेखों का ज़िक्र हुआ है, वे Hofstadter की किताब Metamagical Themas के अध्याय 17~19 में हैं, और Scientific American की उसी शृंखला के दूसरे लेख भी उसमें शामिल हैं
    [0]: https://www.goodreads.com/book/show/181239.Metamagical_Thema...
    किताब का शीर्षक Martin Gardner के Scientific American में लिखे “Mathematical Games” का anagram है, और Hofstadter ने वही शृंखला आगे संभाली थी

    • मुझे यह किताब बहुत पसंद है। Hofstadter की क्लासिक Gödel, Escher, Bach पसंद करने वालों को इसकी ज़ोरदार सिफारिश करता हूँ
    • यह किताब पढ़ने और देखने दोनों में बेहद सुंदर है, और इसमें बहुत-सी रोचक चित्रावलियाँ हैं
  • लेख में कहा गया है कि nil पर car या cdr लागू करने से 0 से भाग देने जैसी त्रुटि आनी चाहिए, लेकिन आधुनिक Lisp में अक्सर अब ऐसा नहीं होता।
    John McCarthy द्वारा परिभाषित मूल Lisp में CAR और CDR, NIL के लिए परिभाषित नहीं थे: <https://dl.acm.org/doi/pdf/10.1145/367177.367199>
    लेकिन Common Lisp और Emacs Lisp (car nil) और (cdr nil) को nil के रूप में परिभाषित करते हैं: <https://www.lispworks.com/documentation/HyperSpec/Body/f_car...>, <https://www.gnu.org/software/emacs/manual/html_node/elisp/Li...>

    • Maclisp में यह कैसा था, यह जानने के लिए Lars Brinkhoff के सार्वजनिक ITS में telnet से लॉग इन करके जाँच की।
      LISP 2156 में (status lispversion) ने /2156 लौटाया, और (car nil) तथा (cdr nil) दोनों ने NIL लौटाया।
    • यह हैरानी की बात है कि गणितीय रूप से डिज़ाइन की गई एक भाषा के जन्म में car और cdr जैसे बेहद ठोस implementation details इतने केंद्रीय थे।
      “List Processor” के सबसे बुनियादी और सबसे प्रसिद्ध operators वास्तव में list पर नहीं, बल्कि cons पर काम करने के लिए बनाए गए थे, जो वह खास machine representation element है जिससे Lisp data structure बनाता है।
      cons को हमेशा list के रूप में नहीं समझा जाता, और list-recursive functions का बेहद महत्वपूर्ण base case भी cons से व्यक्त नहीं होता।
      60 साल बाद भी ज़्यादातर Lisp programs cons operations से भरे हुए हैं, और शायद इसका ज़्यादा सटीक नाम “Cons Processor” होता।
      यह याद दिलाता है कि Lisp उस दौर में पैदा हुआ था जब language और implementation को एक-दूसरे में गुँथा होना पड़ता था, और इसी वजह से computer language को mathematical logic पर आधारित करने की उपलब्धि और भी अधिक चौंकाने वाली लगती है।
    • Scheme में ऐसा नहीं है। nil का CAR या CDR लेने पर त्रुटि मिलती है।
    • दुर्भाग्य से Scheme में nil का car/cdr त्रुटि देता है, इसलिए मेरे जैसे शुरुआती व्यक्ति के लिए code काफ़ी unergonomic लगता है।
      फिर भी Common Lisp की तुलना में मैं Guile Scheme को ज़्यादा पसंद करता हूँ, इसलिए थोड़ा अफ़सोस है।
    • मैं सोच रहा हूँ कि उस language design choice के लिए कोई term है क्या, जिसमें nil पर कुछ लागू करने पर त्रुटि दिए बिना फिर से nil लौटाया जाता है।
      SQL याद आता है, और व्यक्तिगत रूप से मुझे यह अच्छा विकल्प नहीं लगता, इसलिए अगर इसका कोई और नाम नहीं है तो मैं इसे “bleeding nils/NULLs” कहना चाहूँगा।
      खासकर अगर boolean comparison में nil, false के बराबर भी न हो, तो यह और खराब हो जाता है।
      Ruby और Elixir में nil को false की तरह माना जाता है, और Elixir शुद्ध boolean ही लेने वाले and तथा nil को false मानने वाले && को अलग-अलग प्रदान करता है।
      ऐसा डिज़ाइन शुरू में code को साफ़-सुथरा बना सकता है, लेकिन असल त्रुटि वाले गलत तरीके से संभाले गए nil कई call stacks बाद बिलकुल किसी और जगह सामने आ सकते हैं, जिससे debugging बहुत कठिन हो जाती है।
  • इस लेख की Lisp संबंधी जानकारी मुझे पहले से पता थी, फिर भी इसे पढ़ना मज़ेदार लगा। Hofstadter की भाषा में सचमुच एक आकर्षण है।
    खासकर यह मज़ाक बहुत अच्छा लगा कि उसने readers-digest-condensed-version की inverse operation के रूप में rejoyce बनाया, ताकि (rejoyce 'Stately 'Yes) चलाने पर कोई Lisp परी James Joyce द्वारा लिखी गई हो सकती Ulysses की पूरी किताब शुरू से पैदा कर दे।
    इसमें थोड़ा समय लगा, लेकिन हम आखिरकार उस बिंदु तक पहुँच ही गए; और भले ही 2024 का AI, 1983 में उसकी कल्पना से पूरी तरह एक जैसा नहीं है, छोटे seed से text को फिर से उत्पन्न करना आज के AI के लिए काफ़ी उपयुक्त काम है।

  • Lisp को अब भी ऐसी प्रमुख language में माना जाता है जो Hofstadter द्वारा चर्चा किए गए strange loop की अवधारणा को समेट सकती है
    केवल Lisp ही homoiconic language नहीं है, लेकिन जिन languages का लोग वास्तव में उपयोग करना जानते हैं, उनमें यह उस बड़े वर्ग का हिस्सा है जहाँ eval को parse करने के लिए string नहीं लेनी पड़ती
    यह बात खटकती है कि लोग अक्सर Lisp को पूरे functional programming का पर्याय मान लेते हैं
    functional programming से कोई आपत्ति नहीं है, लेकिन Lisp का symbolic character कहीं अधिक दिलचस्प है, और (go tag) सेक्शन से चलने वाला code बनाकर GOTO-शैली का programming भी बहुत आसानी से किया जा सकता है — यह अंतहीन रूप से मज़ेदार है

    • 2000 के दशक में थोड़े समय के लिए mainstream adoption पाने वाली एक और, सचमुच functional homoiconic language XSLT भी थी
      XSLT और XML का उपयोग करके repetitive code सीधे लिखने के बजाय XSLT generate करने वाली metaprogramming क्षमता काफ़ी व्यापक रूप से इस्तेमाल हुई
      हालाँकि, इसकी syntax Lisp की syntax से भी बड़ी समस्या थी
      ऐसी language बनाना आसान नहीं है जिसकी syntax रोज़मर्रा के उपयोग के लिए अच्छी हो और साथ ही abstract syntax tree के रूप में संभालना भी बहुत कठिन न हो, और Lisp इस मामले में अपेक्षाकृत सफल बहुत कम उदाहरणों में से एक है
    • खासकर Scheme के continuation-based programming तक पहुँचने पर functional और non-functional programming की सीमा लगभग अर्थहीन होने जितनी धुंधली हो जाती है
    • यह जानने की जिज्ञासा है कि 2024 का programmer Lisp से ऐसा कौन-सा गहरे स्तर का homoiconic/symbolic support पाता है, जो Python के functools से सहज रूप में नहीं मिलता: https://docs.python.org/3/library/functools.html
      मैं Lisp के बिना symbolic AGI बना रहा हूँ, इसलिए experts से कुछ संकेत सुनना चाहता हूँ
      मेरी समझ में Python पक्ष की सुविधाएँ filter(), map(), reduce() जैसी वे functions हैं जो iterable objects पर दूसरी functions लागू करती हैं; @singledispatch जैसे wrappers जो call को route करते हैं; @cache और partial() जैसी functions जो flow control या performance convenience देती हैं; और wraps() जैसी functionality जो मनमाने ढंग से functions को wrap करती है
      इनमें से ज़्यादातर चीज़ें functions को असामान्य तरीक़े से call करने की convenience जैसी लगती हैं, और Lisp की उस प्रशंसा के स्तर तक पहुँचती नहीं दिखतीं जहाँ “आत्म-चिंतन” को first-class concern की तरह लिया जाता है
      मैं जानना चाहता हूँ कि ऊपर की सुविधाओं से परे Lisp वास्तव में क्या देता है
    • इसकी एक वजह यह भी है कि बहुत से लोग Lisp से केवल academia के माध्यम से परिचित होते हैं, और Lisp पढ़ाने वाले scholars की वास्तविक रुचि Lisp में कुछ बनाकर विकसित करने में नहीं होती
      वे Lisp का उपयोग concepts समझाने के साधन के रूप में करते हैं, और वे concepts प्रायः functional recursion के इर्द-गिर्द घूमते हैं
      Scheme और उसके आसपास की culture भी इसमें भूमिका निभाती है
      Scheme केवल functional language नहीं है, लेकिन यह पहले की Lisp family की तुलना में pure programming पर अधिक ज़ोर देती है, base language में looping constructs के बजाय tail recursion structure देती है, और implementations से tail call optimization की अपेक्षा करती है
  • Common Lisp में भी defalias को macro के रूप में define किया जाए तो इसे Emacs के defalias की तरह इस्तेमाल किया जा सकता है: https://stackoverflow.com/questions/24252539/defining-aliase...

  • Metamagical Themas में छपे Hofstadter के Lisp लेख मुझे पसंद आए थे, और उस series के आख़िरी लेख के code को मैंने workplace study group के लिए Clojure के अनुरूप रूपांतरित करके व्यवस्थित किया था
    [1] http://johnj.com/posts/oodles/

    • यह भी जानने की जिज्ञासा है कि क्या इसका कोई modern Lisp में किया गया अनुवाद उपलब्ध है