- Cognition एक language research project है जिसने Lisp और concatenative languages की read-ahead समस्या से बचने के लिए पूरी तरह postfix पद्धति की antisyntax को चुना है
- इसके core mechanisms — delimiter, ignore, singlet, falias, crank, metacrank — प्रोग्राम को अपने tokenization rules और execution cycle बदलने देते हैं
- bootstrap ऐसी स्थिति से शुरू होता है जहाँ सभी characters को single token के रूप में पढ़ा जाता है, और फिर खुद को ऐसे environment में ले जाता है जहाँ spaces और newlines delimiters के रूप में इस्तेमाल होते हैं
crankऔरmetacrankयह control करते हैं कि tokens को कब evaluate किया जाए और कब stack पर जमा रखा जाए, जिससे#comment,\escape,[quote,(macro जैसी prefix syntax को postfix system के अंदर define किया जा सके- Brainfuck dialect भी अलग parser से नहीं, बल्कि Cognition words और tokenization rules से implement किया गया है, जिससे syntax को ही code बनाकर automate करने की दिशा दिखती है
मौजूदा syntax में Cognition जिन बिंदुओं को समस्या मानता है
- Lisp s-expression और macro system के जरिए शक्तिशाली metaprogramming देता है, लेकिन फिर भी fixed syntax से प्रभावित रहता है
- left parenthesis यह signal है कि right parenthesis आने तक पढ़ना होगा, इसलिए language के अंदर parentheses की भूमिका बदलना कठिन है या कुछ implementations में असंभव है
- पहले से पढ़े गए tokens को बाद में अलग तरीके से delimit करना हो तो काफी string processing चाहिए
- current input देखकर आगे और पढ़ना है या नहीं, यह प्रक्रिया syntax है, और जैसे ही default read-ahead मान लिया जाता है, आप किसी खास syntax form से बंध जाते हैं
- Cognition इससे बचने के लिए पूरी तरह postfix पद्धति की antisyntax इस्तेमाल करता है
- यह concatenative languages जैसा है, लेकिन Cognition के अनुसार आम concatenative languages में भी square brackets या string quote characters के कारण read-ahead समस्या होती है
- Racket का macro system runtime dynamic syntax change नहीं, बल्कि preprocessing इस्तेमाल करने वाला तरीका माना गया है
Project और basic idea
- Cognition, Matthew Hinton के साथ कई महीनों से चल रहा एक active research project है
- implementation repository cognition-rust पर है, और repository में language पर एक paper भी है
- इसे समझने में parsing, tokenization और syntax की background मददगार होती है
- explanation “baremetal cognition” code से शुरू होकर Stem जैसी syntax में develop होने का flow follow करती है
Baremetal Cognition और tokenization
- baremetal Cognition ऊपर से Brainfuck जैसा दिखता है, लेकिन ज्यादा मजबूत metaprogramming कर सकता है
- बहुत छोटा bootstrap code spaces और newlines तक को meaningful तरीके से इस्तेमाल करता है, और initial state में हर single character token के रूप में पढ़ा जाता है
- Cognition मूल रूप से stack-based design है, लेकिन stack से अधिक generic अर्थ में container term इस्तेमाल करता है
- default environment में खास falias को छोड़कर कोई word automatically execute नहीं होता
-
delimiter, ignore, singlet
- delimiter tokenizer को एक token का end और अगले token की start पहचानने देता है
- single-character delimiter list को Cognition code के अंदर modify और read किया जा सकता है
- ignore characters प्रत्येक read-eval-print loop के token collection start phase में skip किए जाते हैं
- default यह है कि सभी characters delimiter हैं और कोई ignore character नहीं है
- delimiter, singlet, ignore lists whitelist/blacklist flags से अपना behavior बदल सकती हैं
- default setting है: blacklist delimiter नहीं, whitelisted singlet नहीं, whitelisted ignore characters नहीं
- singlet तीसरी tokenization category है, जो खुद को token में शामिल करके token collection खत्म करती है
-
falias
- falias उन words की list है जो container पर आते ही execute हो जाते हैं
- default falias
fcontainer में जमा नहीं होता, बल्कि container के top word को execute करता है - example में जब
f,dको execute करता है, तोddelimiter list को word की string value में बदल देता है - इसके बाद
l,g,t,dजैसे characters को क्रमिक रूप से non-delimiter बनाया जाता है, और spaces व newlines को delimiter तथा ignore में बदलने वाला bootstrap आगे चलता है
Bootstrap द्वारा बनाया जाने वाला execution environment
- initial bootstrap delimiter और ignore rules बदलकर अंत में ऐसा environment बनाता है जहाँ spaces और newlines token delimiters होते हैं, और token start phase में spaces और newlines ignore किए जाते हैं
- इसके बाद
1औरcrankपढ़े जाते हैं, औरf,crankको execute करके crank 1 environment में प्रवेश कराता है - इस प्रक्रिया का core point यह है कि execution के दौरान tokenization का तरीका बदला जा सकता है
- delimiter, singlet, ignore changes को program से automate किया जा सकता है
- यह postfix है और read-ahead नहीं है, इसलिए expression evaluation से पहले एक या अधिक tokens को pre-parse करने की जरूरत नहीं होती
- falias prefix words या default word auto-execution के बिना भी किसी specific word को execute करने देता है
crank और metacrank
- crank वह mechanism है जो तय करता है कि stack पर tokens को किस cycle में execute करना है
crankword एक number को argument के रूप में लेता है, और उसके बाद container पर आने वाले हरn-वें word पर stack top को execute करता है- bootstrap के अंत का
1 crankऐसा environment बनाता है जहाँ हर token evaluate होता है 5 crankstate में पांचवां token आने तक words जमा हो सकते हैं
- bootstrap के अंत का
- example code
2crankनाम का word बनाने के लिएunglue,swap,quote,prepose,defका उपयोग करता हैunglueword value लाता है, औरcrankजैसे builtin के function pointer भी ला सकता हैpreposeStem केcomposeजैसा है, लेकिन आगे जोड़ता है और VMACRO में डालता हैdef2crankको इस तरह define करता है कि वह stack पर2रखे औरcrankbuiltin को call करे
-
Cognition के container और macro
- Stem में words को सीधे stack पर रखा जा सकता है, लेकिन Cognition में unevaluated words container के अंदर जाते हैं
- इस design की वजह से
composeजैसे words single-word container और दूसरे containers को consistent API से handle कर सकते हैं - Cognition का macro, Stem quote से अलग है
- macro evaluate होने पर crank को ignore करता है और अंदर के सभी elements evaluate होते हैं
- किसी word से bound macro को evaluate करने पर पूरा macro crank से independent होकर execute होता है और cranker केवल एक बार बढ़ता है
- macro crank-independent code और optimization-oriented expansion के लिए useful है
-
metacrank
n m metacrankstack मेंnpositions नीचे वाले element के लिए periodmकी evaluation set करता हैcrank,0 m metacrankजैसा ही है- प्रति token केवल एक metacrank evaluate हो सकता है, और lower metacrank को priority मिलती है
- metacrank और crank सिर्फ file tokens पर नहीं, बल्कि word definitions को recursively evaluate करने की प्रक्रिया पर भी लागू होते हैं
- metacrank “n tokens पढ़ने के बाद इस token को execute करना है” जैसी direct syntax manipulation संभव बनाता है
- prefix word program करने के बाद जरूरत न हो तो उसे
undefकिया जा सकता है - किसी specific end character के बजाय specific token count के बाद रुकने वाला prefix character भी बनाया जा सकता है
- user input को math program में डालकर उसके output को metacrank जैसे syntax system को pass किया जा सकता है
Stem dialect में विकसित होने की प्रक्रिया
- Cognition bootstrap के बाद language के अंदर धीरे-धीरे Stem v2 के करीब syntax build करता है
- पहले
fको falias list से हटाकर केवलingछोड़ा जाता हैfको सीधे stack पर रखें तो वह execute हो जाता है, इसलिएffबनाकर string को आधा काटकर दोfहासिल किए जाते हैं- इसके बाद
fको false के बराबर empty word के रूप में define किया जाता है
-
#comment#character पहला code example है जो वास्तविक prefix की तरह काम करता है- यह comment character newline से पहले तक के text को discard करने वाले prefix की तरह काम करता है, यानी parser आगे पढ़ने वाली syntax बनाता है
- implementation
geti,getd,gets,crankbase,halt,VMACRO cast,singlet,delimआदि को combine करता है geti,getd,getsक्रमशः ignore, delimiter, singlet को strings के रूप में लाते हैंhaltसभी metacrank को 0 बना देता हैVMACRO caststack top के container को macro में बदलता है#definition tokenization rules बदलने के बाद भविष्य में tokenize होने वाले word पर#call करती है, उस comment को drop करती है, और फिर original crank और metacrank पर लौटती है
-
escape, quote, macro
\को escape character के रूप में define किया जाता है, जिससे evaluate होने वाला word भी stack पर चढ़ाया जा सके- इसके बाद
[quote definition जोड़ी जाती है, फिर उसी quote का उपयोग करके self-redefine होकर recursive quote वाली बेहतर[definition बनाई जाती है - postfix
defकी वजह से पुरानी definition का इस्तेमाल करके नई definition बनाई जा सकती है - यह pattern low-level Cognition में अक्सर इस्तेमाल होने वाला development तरीका है
(को macro bracket के रूप में define किया जाता है- macro को automatically expand होने के लिए बनाया गया है, इसलिए already expanded macro को word से bind करना अधिक efficient माना जाता है
- functionally यह उसी तरह evaluate होता है
expandquote या macro के अंदर word definitions कोunglueसे recursively expand करता है- पहले basic
expanddefine किया जाता है, फिर अधिक general cases handle करने के लिएexpandखुद का उपयोग करके खुद को redefine करता है
Brainfuck dialect
- Cognition evolved Stem dialect के ऊपर Brainfuck dialect define करता है
- execution example
../crank -s 2 bootstrap.cog helloworld.bf brainfuck.cogहै brainfuck.cogसामान्य अर्थ में Brainfuck parser नहीं है- यह Brainfuck words define करता है
- Brainfuck को tokenize करता है
- Cognition native environment में execute करता है
- यह example दिखाता है कि Cognition syntax से alternative syntax आसानी से define की जा सकती है
- Cognition symbols पढ़कर उनके हिसाब से behavior तय करने के बजाय, metacrank का उपयोग करने वाले prefix characters को ही words के रूप में define करता है, और syntax को word definitions के अंदर डालता है
dialect dialect की कल्पना
mkprefixजैसे word की कल्पना की जा सकती है- उदाहरण के लिए,
[और]दो input words और कोई operation लेकर,[को ऐसा automatically define करने वाला word, जो]मिलने तक उस operation को apply करे
- उदाहरण के लिए,
- ऐसी कल्पना इसलिए संभव है क्योंकि
metacrankऔरdefदोनों ordinary words हैं d,i,sसहित सब कुछ word है, इसलिए syntax implementation process को automate करने वाला अधिक abstract dialect बनाया जा सकता है- standard library में अभी यह implement नहीं है, लेकिन Matthew Hinton के साथ standard library की संभावना के रूप में चर्चा किए गए items हैं
- abstract words को automatically generate और call करने वाला metaword
- current wordlist को automatically abstract करने के लिए word-generator search
- problem solving के लिए abstraction framework को निर्देश देने का तरीका
Syntax को code की तरह handle करने की संभावना
- Cognition में string processing tokenizer post-processing जैसी है, इसलिए string operations का मजबूत अर्थ है
- संभावित application areas के रूप में Symbolic AI, syntax और grammar research, language और metalanguage prototype experiments बताए गए हैं
- config files पढ़ने वाले programs, Cognition-based shell, Cognition-based operating system जैसे ideas भी हैं
- core point यह है कि Cognition “syntax as code” संभव बनाता है
- syntax को dynamically program किया जा सकता है
- syntax generation को खुद automate किया जा सकता है
- Metastack और
cdजैसी concepts को cover नहीं किया गया है, और इन्हें follow-up posts के topics के रूप में छोड़ा गया है
1 टिप्पणियां
Hacker News की राय
उदाहरण के लिए, Racket में आप Datalog syntax इस्तेमाल करते हुए भी ऐसा embedded Datalog implementation बना सकते हैं जो दूसरे Racket modules के साथ interoperable हो, और basic data model नहीं बदलता
यह S-expressions में फंसे बिना metaprogramming करने देता है, और फिर भी processing को ज्यादा ऊंचे level पर रखता है
इस तरह की syntax bootstrapping बढ़िया है और research के लिहाज से valuable है, लेकिन यह Racket approach से मूल रूप से बेहतर है या नहीं, पता नहीं
Lisp, Scheme, Racket macros आम तौर पर AST पर काम करते हैं, लेकिन Rhombus AST जैसी चीज़ "shrubbery" पर काम करता है, जिसमें कुछ parsing decisions बाद के लिए टाल दिए जाते हैं, जिससे syntax extension में थोड़ी flexibility मिलती है
संदर्भ: https://docs.racket-lang.org/guide/hash-reader.html, https://docs.racket-lang.org/datalog/datalog.html, Rhombus paper https://doi.org/10.1145/3580417
#langCL readtable से ज्यादा convenient हैसिर्फ readtable से भी C compiler implement करने जितना powerful है: https://github.com/vsedach/Vacietis
निजी तौर पर "metacrank" वाला हिस्सा देखकर मैं जोर से हंस पड़ा
Emacs Lisp, Common Lisp, ISLISP में macros बस कोई data लेते हैं और कोई data लौटाते हैं, और AST जैसी कोई concept नहीं होती
(foo-macro ...)call करने पर...कोई भी arbitrary data हो सकता हैउदाहरण के लिए
(defmacro rev (&rest items) (reverse items))macro call के source arguments की list लेकर उसे उलट देता हैइसे
(rev 1 2 3 4 +)या(rev (rev 10 n -) (+ a 20 b) (rev 30 a *) list)की तरह इस्तेमाल कर सकते हैं, और असल में lists, numbers और symbols pass होते हैंयह न text है, न AST, और
evalको computed data पास करने पर भी यह उसी तरह काम करता हैLisp का reader मूल रूप से data layer यानी symbolic expressions पढ़ता है, और EVAL, macros और दूसरे features मुख्यतः data लेते हैं
compiler internally AST representation बना सकता है, लेकिन यह implementation की स्वतंत्रता है, और Lisp language आम तौर पर text syntax के बजाय data syntax पर defined होती है
Lisp interpreter runtime में text नहीं, S-expressions process करने वाला "List Processor" है, और
COMPILEभी text नहीं बल्कि S-expressions लेता हैRacket और Scheme के अपने अलग macro systems हैं
वास्तविक project Cognition का जिक्र आने से पहले 300 से ज्यादा शब्द आ जाते हैं, और Lisp की चर्चा अच्छी है, लेकिन शक है कि क्या वह project का सबसे महत्वपूर्ण हिस्सा है
कोई informative article पढ़ते समय मन लगातार पूछता है, "क्या यह मेरे समय के लायक है?", इसलिए document को शुरुआत से ही बताना चाहिए कि वह किस बारे में है
"Cognition एक नई language है जो user-modifiable syntax को explore करती है" जैसा कुछ काफी होता, लेकिन पहले चार paragraphs के बाद भी यह तय करना मुश्किल था कि आगे पढ़ना worth it है या नहीं
अगर समय पैसा है, तो इस article को पढ़ने में लगा समय waste माना जा सकता है
Internet की हर content से यह उम्मीद करने के बजाय कि वह personal taste के हिसाब से हो, मुझे लगता है मौजूद formats के साथ adapt करना बेहतर है
Text video जैसा medium नहीं है जिसे केवल sequentially consume करना पड़े, इसलिए diagonally skim करके interesting हिस्से खोज सकते हैं, न मिलें तो छोड़ दें, मिलें तो शुरुआत पर लौटकर पढ़ लें
लिखने के विविध तरीके बेहतर हैं क्योंकि वे हमें consciously information filter करने को मजबूर करते हैं; केवल passively consume करने से दिमाग सुस्त हो जाता है
हालांकि अगर यह video होता तो मैं सहमत होता
Video देखने से पहले ही तय करना पड़ता है कि समय लगाना है या नहीं, और 2x speed या 5–10 seconds skip करना थोड़ी मदद करता है, लेकिन समस्या हल नहीं करता
पहले problem explain की गई है और उसके बाद solution introduce किया गया है
कुछ sentences पढ़कर ही समझ आ गया था कि यह एक Don Quixote- जैसी solution है उस "problem" के लिए जिसकी 99.999% लोगों को परवाह नहीं होगी, जिनमें मेरे जैसे लोग भी हैं जिन्होंने Lisp का नाम सुना है लेकिन Emacs config files के बाहर उसे कभी इस्तेमाल नहीं किया; फिर भी मैं पढ़ता गया
अगर यह section न होता तो आगे की चीजें समझना ज्यादा मुश्किल होता
अगर वह background न पता हो तो पूरे article का context छूट सकता है, और यह भी judge करना मुश्किल है कि यह strawman argument है या नहीं
इसलिए पूरा project बहुत narrow जरूरत के लिए बना लगता है, जबकि title कहीं ज्यादा general और काफी interesting concept जैसा दिखता है
पहले दो sentences के भीतर ही यह सामने आ जाता है कि कौन-सी problem solve करनी है, और मेरी रुचि आंकने के लिए यह proposed introduction से कहीं ज्यादा useful है
हालांकि व्यक्तिगत रूप से, programming purity की सीढ़ी को ऊपर देखते हुए Forth ही शायद मेरी philosophical purity झेलने की सीमा है
आगे भी और ज्यादा dark magic cover करते रहेंगे
बस लगभग सभी languages, जिनमें सारी Lisp भी शामिल हैं, quotation को गलत handle करती हैं, और मजेदार बात यह है कि
m4इसका exception हैLisp इस समस्या को macros के जरिए bypass करता है, जिससे object language के वाक्यों में व्यक्त meta language के वाक्यों को quotation को नज़रअंदाज़ करके handle किया जा सके
यह समस्या object language और meta language दोनों में whitespace को atom का अंत मानने और दोनों में फर्क न करने से पैदा होती है
पूरी तरह postfix anti-syntax वाला Cognition का तरीका concatenative programming languages जैसा दिखता है, लेकिन postfix language prefix language का dual है और वही समस्या झेलता है
या तो हर symbol की arity पहले से तय करनी होगी और higher-order functions नहीं इस्तेमाल करने होंगे, या फिर tree को serialize कर सकने वाले delimiter की एक जोड़ी चाहिए होगी
implicit 0-ary stack पर निर्भर रहना, depression ठीक करने के लिए lobotomy करने जैसा है
हमने कितना नया बनाया है, यह हमें भी नहीं पता, और अगर आपको लगता है कि Lisp से वह किया जा सकता है जो हम कर रहे हैं, तो चाहें तो हमें गलत साबित कर दें
m4में quotation कैसे अलग है, इसके उदाहरण देखने में रुचि हैदावा अपने-आप में दिलचस्प है, लेकिन और ठोस चीज़ चाहिए
जैसे lobotomy higher-order processing क्षमता घटा देती है, वैसे ही command string calculation के सबसे primitive तरीके पर लौटना भी वैसा ही माना जा सकता है
https://www.hpmuseum.org/rpnvers.htm
खासकर यह कि वह mechanism बहुत छोटा है
मैं language expert नहीं हूं, इसलिए नहीं जानता कि इसमें नई बात है या नहीं, लेकिन लेख पढ़ते हुए हर बार जब लेखक एक पहाड़ी पार करते थे, तो नई संभावनाओं की पर्वत-श्रृंखला खोजने की खुशी महसूस होती थी
अगर मैंने सही समझा है, तो बात यह है कि Cognition से सचमुच सोचने वाली मशीन बनाई जा सकती है
program को रोककर नए command से restart किए बिना, वह नए input के आधार पर खुद नए subroutines लिख और execute कर सकता है
यानी program नई abstractions बनाते हुए और नए APIs से जुड़ते हुए सीख और adapt कर सकता है
मेरे लिए यह बड़े neural networks या नई learning techniques से ज़्यादा दिलचस्प है
Common Lisp में reader macro होता है, जिससे आप अपनी इच्छा के अनुसार syntax बदल सकते हैं, और reader macro से Fortran syntax पढ़ने वाला Fortran compiler भी मौजूद है
Common Lisp में read-time reader macro, macros, और compile-time compiler macro होते हैं, और इन सभी macro languages की language Common Lisp ही है
metaprogramming का macros या syntax से बहुत ज़्यादा लेना-देना नहीं है; यह types, interfaces, classes, methods आदि की semantics और अर्थ को manipulate करने की क्षमता को बताता है
अगर CL अपने-आप में पर्याप्त शक्तिशाली न हो, तो इसके लिए CLOS, यानी Common Lisp Metaobject Protocol मौजूद है
CL reader macro से अलग tokenizer इस्तेमाल किया जा सकता है, लेकिन tokenizer switch बताने के लिए read table के अंदर expression देना पड़ता है
Cognition में ऐसा दिखता है कि function call करने पर caller context का tokenizer बदल जाता है
हमें Turing machine या lambda calculus जैसी चीज़ों से ऐसे काम का महत्व इसलिए सिखाया गया था कि दिखाया जा सके कि high-level language foundation language के बराबर है, और इसलिए पहली के बारे में किए गए reasoning को दूसरी पर भी लागू किया जा सकता है
जो पहला और एकमात्र उदाहरण दिमाग में आता है, वह halting problem है
practical scale पर, अगर basic language में memory leaks न होने का proof दे दें, तो क्या derived language में भी leaks न होने की बात कही जा सकती है?
ऐसे bootstrapping के क्या फायदे हैं, यह जानने की उत्सुकता है
अगर जवाब बस Everest चढ़ने जैसा "क्योंकि वह वहां है" है, तो उसका भी सम्मान है
dfके बाद का space, line 3 का space, और newline महत्वपूर्ण हैं—इस हिस्से पर आते ही मेरे लिए यह "धन्यवाद, पर नहीं" हो गयापिछली line के अंत के तीन space characters व्यंग्य दर्शाते हैं, और जहां trailing whitespace को आसानी से अलग नहीं पहचाना जा सकता, वहां इन्हें literal रूप में पढ़ा जाए
जिस bootstrap हिस्से का आपने ज़िक्र किया, वह असल में reader को बताता है कि space और newline को delimiter की तरह treat करें
यानी delimiter घोषित करने वाले section में space का अर्थ होने पर आप शिकायत कर रहे हैं
बेशक ऐसा सोचने का आपको अधिकार है, लेकिन उत्सुकता होती है कि इसे बेहतर करने का कोई तरीका था या नहीं
एक बार के लिए literal space इस तरह अर्थ लिए बिना यह करने का कोई तरीका मुझे नहीं सूझता
क्या आपको लगता है कि syntax के बिना "sentence this without you syntax read can" जैसा वाक्य पढ़ा जा सकता है?
Cognition पूरी तरह postfix anti-syntax इस्तेमाल करता है, लेकिन postfix भी syntax है
German बोलने वालों से वाक्य के अंत में आने वाले verb के बारे में पूछ लें
पहले example में भी operands और operator का order महत्वपूर्ण है, और वही तो syntax है
यह बेतहाशा compact language बनाने की कोशिश लगती है और APL की बहुत याद दिलाती है
लेखकों के लिए एक hint: आपने syntax हटाई नहीं है, बस इसे इंसानों के लिए पढ़ना और समझना मुश्किल बना दिया है, और readability और understandability programming में महत्वपूर्ण तत्व हैं
ऐसा लगा जैसे पैरों के नीचे के नियम लगातार बदल रहे हों; rules और words introduce होते हैं और फिर मनमाने ढंग से redefine हो जाते हैं
कुल मिलाकर इसमें Numberwang जैसा माहौल है, इसलिए यह satire जैसा लगने की एक वजह शायद यही है
एक और बड़ी वजह यह है कि bootstrapping step हास्यास्पद हद तक लिखा गया है, और वह शायद जानबूझकर है
साफ है कि इसमें कुछ गहरा है, लेकिन और कड़क coffee पीकर फिर से पढ़ना पड़ेगा
मैं इस लेख का लेखक हूं; समस्या यह है कि बताने के लिए वाकई बहुत कुछ है
Matthew और मैंने इस language design पर 3 हफ्ते तक रोज़ कई-कई घंटे चर्चा की, और जो लोग मुझे सच में नहीं जानते, उनके लिए भरने को context भी बहुत है