Cognition प्रोग्रामिंग भाषा का परिचय
समस्या
- Lisp प्रोग्रामर यह दावा करते हैं कि वे S-expression code और functional macro system से meta-programming और generalized systems बना सकते हैं।
- लेकिन Lisp में एक मूलभूत समस्या है
- meta-programming और programming एक समान नहीं हैं, इसलिए Lisp में हमेशा कठोर syntax रहता है (जैसे parenthesis या look-ahead के लिए कुछ निश्चित character)
- left parenthesis Lisp को यह बताता है कि जब तक right parenthesis नहीं मिलता, पढ़ना जारी रखना चाहिए
- इससे भाषा के अंदर left/right parenthesis बदलना लगभग असंभव हो जाता है (सैद्धांतिक रूप से नहीं, लेकिन कुछ implementations में इसे बदलना संभव नहीं होता)
- इससे भी अधिक महत्वपूर्ण यह है कि इन्हें बाद में केवल string processing के बिना बदलना संभव नहीं होता
- अन्य भाषाओं में भी token देखकर आगे क्या पढ़ना है तय करने के अन्य तरीके होते हैं
- इसी प्रक्रिया को syntax कहते हैं
- Cognition पूर्ण postfix notation (antisyntax) इस्तेमाल करके अलग रास्ता अपनाता है
- यह concatenative programming language जैसा दिखता है, लेकिन concatenative languages में भी दो प्रमुख समस्याएँ हैं
- left/right bracket characters की जरूरत पड़ती है (वास्तव में यह prefix notation जैसा है)
- strings के लिए quote character
- यह सामान्य भाषाओं के लिए उपयुक्त नहीं है
- Lisp की C-style syntax implementation में भी वही समस्याएँ दिखीं (escape character की अधिकता, और किसी token की शुरुआत/अंत अलग करने के लिए space character की जरूरत)
- Racket में macro system है, लेकिन यह runtime में dynamic नहीं है और preprocessing का सहारा लेता है
Cognition परिचय
- यह project Matthew Hinton के साथ कई महीनों के शोध के बाद बना
- लक्ष्य है कि पूर्ण postfix notation को इस्तेमाल करके ज्ञात सबसे generalized syntax systems में से एक बनाया जाए
- syntax, tokenization और parsing की पृष्ठभूमि की जरूरत पड़ सकती है, लेकिन इसे आसान तरीके से समझाने की कोशिश की गई है
- Repository: https://github.com/metacrank/cognition
Baremetal Cognition
- Baremetal Cognition Brainfuck जैसा है, लेकिन इसमें गंभीर स्तर का meta-programming संभव है
- bootstrap कोड उदाहरण:
ldfgldftgldfdtgldf dfiff1 crank f
- whitespace और newline यहाँ महत्वपूर्ण हैं
- दूसरी लाइन में
df के बाद space है
- तीसरी लाइन में space character शामिल है
- इससे delimiter और ignore नाम के दो नए concepts introduce किए जा सकते हैं
Tokenization
- delimiter (डिलीमीटर) tokenizer को token की शुरुआत और अंत को अलग करने में मदद करता है
- single-character tokenizer सूची सार्वजनिक है और Cognition के भीतर से editable/readable है
- ignored character वह होता है जिसे read-eval-print loop के पहले चरण में tokenizer पूरी तरह छोड़ देता है
- यानी token collection शुरू करते समय सेट की गई ignored character सेट को skip किया जाता है
- डिफ़ॉल्ट रूप से सभी characters delimiter होते हैं और कोई भी ignored नहीं होता
- delimiter और ignored सूची दिए गए characters के लिए blacklist/whitelist toggle उपलब्ध कराती है (जो संक्षिप्तता और व्यावहारिकता देती है)
Falias
- Falias वह शब्द सूची है जो stack पर रखे जाने पर execute होती है
- सभी Falias stack के शीर्ष को execute करती हैं (Stem के
eval के equivalent)
f default Falias है; यह stack पर नहीं रखा जाता और stack शीर्ष पर मौजूद d को execute करता है
d delimiter सूची को शब्द की string value में बदल देता है (यानी केवल l character को delimiter सूची से हटाता है)
- डिफ़ॉल्ट environment में special Falias छोड़कर कोई शब्द execute नहीं होता
डिलीमीटर नोट्स
- delimiter के साथ एक रोचक नियम है
- यदि tokenization loop किसी character को ignore नहीं करता, तो delimiter character वर्तमान token का हिस्सा बनकर आगे बढ़ता रहता है
- यह singlet के उलट है (जो token में खुद को शामिल करके skip करके token collection समाप्त करता है)
- blacklist सेटिंग भी की जा सकती है
- delimiter, singlet और ignored सूची को blacklist/whitelist किया जा सकता है
- डिफ़ॉल्ट रूप से blacklist किए गए delimiters, whitelist किए गए singlets और whitelist किए गए ignored characters मौजूद नहीं होते
- अन्य सभी characters वर्तमान token का भाग बनते रहते हैं और नए characters जोड़ते रहते हैं जब तक delimiter या singlet नियम loop रोक न दे
bootstrap कोड जारी
ldf
l को non-delimiter बनाया जाता है
gldftgldfdtgldf dfiff1 crank f
d delimiter होने के कारण gl stack पर रख दिया जाता है, और Falias f call होकर gl को non-delimiter बना देता है
tgl stack पर रखा जाता है और df द्वारा non-delimiter बना दिया जाता है
dtgl stack पर रखा जाता है और \\ndf द्वारा newline (\\n) सिर्फ non-delimiter बनता है (newline वास्तविक कोड में मौजूद है)
- delimiter नियम से space character और
\\n stack पर रखे जाते हैं (तीसरी लाइन में space शामिल है)
- एक और
\\ \\n शब्द tokenize होता है
- वर्तमान stack इस प्रकार है (नीचे से ऊपर की ओर):
3. dtgl
2. [space character]\n
- [space character]\n
df \\ \\n को non-delimiter सेट करता है
if \\ \\n को ignored character सेट करता है (tokenization शुरू होते ही ignore)
f dtgl execute करके delimiter के whitelist/blacklist विभाजन को store करने वाला dflag toggle करता है
- अब सभी non-delimiter characters delimiter बन जाते हैं और सभी delimiters non-delimiter बन जाते हैं
- अंत में space और newline टोकन delimiter बनते हैं और tokenization शुरू में ignored हो जाते हैं
- इसके बाद
1 tokenized होकर stack पर आता है, फिर crank शब्द tokenized होने पर f द्वारा execute होता है (1 इस केस में number माना जाता है, लेकिन Cognition में हर चीज़ शब्द है)
- bootstrap sequence पूरा!
crank क्या करता है, यह अगले सेक्शन में बताया गया है
बूटस्ट्रैपिंग सारांश
- Cognition में tokenization approach को programmatic तरीके से runtime पर बदलना संभव है
- दूसरी भाषाओं में यह संभव नहीं है
- किसी बाहरी भाषा के लिए tokenizer को Cognition के अंदर प्रोग्राम करके चाहने पर tokenization किया जा सकता है
- postfix notation और look-ahead न होने की वजह से यह संभव है
- expression evaluate करने से पहले एक से अधिक tokens parse करने की जरूरत नहीं पड़ती
- Falias की मदद से बिना prefix शब्द या base शब्द को सीधे execute किए शब्द execute किए जा सकते हैं
Crank
- metacrank system stack पर शब्द execute करने का default तरीका सेट करने की सुविधा देता है
crank शब्द एक number argument लेता है और stack पर n शब्द रखे जाने पर stack शीर्ष को execute करता है
- उदाहरण कोड (जब
crank 1 सेट हो):
5 crank 2
crank 2 crank
1 crank unglue swap quote prepose def
crank 1 environment में token evaluation के दौरान f का उपयोग बंद रखा जा सकता है
- प्रत्येक tokenized शब्द के अनुसार 1 शब्द evaluate होता है
- क्योंकि syntax लाइन breaks और spaces से विभाजित कर program किया गया है, इसलिए कोड सीधे समझ आता है
- कोड
5 evaluate करने की कोशिश से शुरू होता है (यह builtin नहीं है, इसलिए खुद को ही evaluate करता है)
crank ऐसा सेट किया गया है कि stack में 5 शब्द होने पर execute हो
2crank, 2, crank, 1 सभी stack पर पड़े हैं (crank 5 सेट होने के कारण यहाँ crank builtin होने पर भी execute नहीं होता):
4. 2crank
3. 2
2. crank
- 1
crank पाँचवाँ शब्द है, इसलिए execute होता है (crank 1 सेट के कारण)
unglue एक builtin है जो stack शीर्ष पर मौजूद शब्द (1 से चुना गया) का value लेता है
- यानी
crank builtin के साथ जुड़ा function pointer लेता है
- stack इस समय इस तरह है:
3. 2crank
2. 2
- [CLIB]
- CLIB वह function pointer है जो
crank builtin को point करता है
swap execute:
3. 2crank
2. [CLIB]
- 2
quote (stack शीर्ष को quote करने वाला builtin) execute:
3. 2crank
2. [CLIB]
- [2]
prepose (stem के compose जैसा, लेकिन आगे रखकर VMACRO में रखने वाला) execute:
2. 2crank
- ([2] [CLIB])
def call
2 को stack पर रखता है और crank builtin के function pointer को call करने वाला शब्द 2crank define करता है
- VMACRO क्या है और Cognition stack तथा Stem stack के बीच का अंतर समझाने की ज़रूरत है
Stem के साथ अंतर
- Stem stack में शब्द सीधे stack पर रखे जा सकते हैं
- Cognition में शब्द evaluate नहीं होते, पहले container में जाते हैं और फिर stack पर रखे जाते हैं
- Stem में
compose जैसे शब्द शब्द (या single-word वाले container) और अलग container पर काम करते हैं
- इससे Cognition का API अधिक consistent बनता है
cd शब्द भी इसी concept का उपयोग करता है
मैक्रो
- Stem quote और Cognition container का एक और अंतर
- macro evaluation में macro के अंदर की सभी चीजें evaluate होती हैं और crank ignore होता है
- शब्द पर bind किए जाने पर, उस शब्द के eval होने पर
1 टिप्पणियां
Hacker News टिप्पणियाँ
कुछ प्रमुख टिप्पणियों का सार इस प्रकार है: