- Raku एक पूरी तरह परिपक्व एकल design से ज़्यादा, कई ideas को सीधे आज़माने वाली language features की research lab जैसा है, इसलिए दूसरी भाषाएँ जिन experiments को अपना सकती हैं, वे एक जगह देखे जा सकते हैं
- Junctions संभावित values के set पर operations को propagate करते हैं और फिर
all·any·oneजैसे boolean quantifiers में fold करके जटिल conditions को संक्षेप में व्यक्त करते हैं - Whatevers का
*infinite ranges, anonymous functions, और list length-based indexing में इस्तेमाल होता है, जिससे concise लेकिन अपरिचित code style बनता है - Raku regex ने PCRE compatibility छोड़ने के बदले composable grammars और value separators, readable lookahead, default whitespace ignoring जैसी सुविधाएँ दी हैं
- Hyperoperators, Pair Syntax, Slangs, RakuAST, Rakudo Star तक देखें तो Raku syntax experiments से लेकर distribution approach तक व्यापक रूप से experiment करने वाली भाषा है
Raku भाषा features की research lab जैसी क्यों दिखती है
- एक साल से ज़्यादा Raku को सच में इस्तेमाल करने के बाद, Raku “language features के लिए research lab” जैसी भाषा लगती है
- पाँच concurrency models और किसी काम को करने के कई तरीके “देखें क्या होता है” वाली experimental प्रकृति दिखाते हैं
- बहुत-सी features अजीब तरीके से interact करती हैं और edge cases ज़्यादा हैं; वजह यह भी है कि 100 experiments चलाने की तुलना में उन्हें polish करके साथ में काम कराना कहीं ज़्यादा मुश्किल है
- यहाँ जिन features पर बात है, वे Raku-style experiments हैं जिन्हें कभी दूसरी programming languages में भी देखा जा सकता है
Junctions: संभावित values का superposition और boolean quantifiers
- Junctions संभावित values के superposition को दर्शाते हैं, और junction पर operation लगाने से वही operation अंदर की सभी values पर लागू होता है
2|10any(2, 10)बन जाता है2&10 + 3all(5, 13)बन जाता है(1&2) + (10^20)all(one(11, 21), one(12, 22))की तरह combine होता है
- Junctions का मुख्य उपयोग
all,anyकी तरह boolean formulas व्यक्त करना है- junction को destructure करने का कोई तरीका नहीं है
- असल में इस्तेमाल करने के लिए पहले उसे boolean में fold करना पड़ता है
sojunction को boolean में force-convert करता हैso (1&2) + (10^20) < 15Trueहैso (1&2) + (10^20) > 0Falseहै
- Raku का
list.allarguments लेने वाला method नहीं, बल्कि list को junction में बदलने वाला no-argument method है<1 2 3>.allall(1, 2, 3)बन जाता हैis-prime($x)लगाने पर यह हर value पर लागू होकरall(False, True, True)जैसा बनता है
- Junctions को combine करके
uniqueजैसा behavior भी बनाया जा सकता है- “क्या हर element ठीक एक element के बराबर है” को
{.all == .one}से व्यक्त किया जा सकता है <1 2 3 7>true है, और<1 2 3 7 2>false है
- “क्या हर element ठीक एक element के बराबर है” को
Whatevers: * से बनने वाली infinite ranges और anonymous functions
- Whatevers का
*Raku में कई भूमिकाएँ निभाने वाला whatever symbol है - range या sequence में
*का मतलब boundary न होना है1..*1..Infहै(2,4,8...*)[17]262144है
*वाली expression anonymous function में promote हो जाती है- इस behavior को whatever-priming कहा जाता है
- result
WhateverCodeहोता है, और type को छोड़ दें तो यह दूसरे functions से अलग नहीं होता (* + 10)(2)12है(^10).map(* % 2)0 1 0 1 ...pattern बनाता है
- अगर expression में दो
*हों, तो हर एक अलग positional argument बनता है(2, 30, 4, 50).map(* + *)(32, 54)return करता है- यह behavior tricky Fibonacci definition में उपयोगी है, लेकिन यह हर
*को same value मानने वाले तरीके से बेहतर है या नहीं, इसका पक्का भरोसा नहीं है
- Raku के कई methods functions ले सकते हैं, इसलिए priming का व्यापक उपयोग होता है
l[*-1]negative index जैसा दिखता है, लेकिन असल में[]list length को function में पास करके calculated index lookup करता है- list length 10 हो तो
l[*-1]l[10-1], यानी last element बनता है l.head(2)पहले दो elements है, औरl.head(*-2)last two elements को छोड़कर बाकी सब है
[]में कोई दूसरा function पास करने से ring buffer जैसी structures भी आसानी से implement की जा सकती हैं@x[95 % *]--list length का उपयोग करके position calculate करता है
Regex: PCRE compatibility छोड़कर composable grammar
- Raku POSIX regex या PCRE से अलग नई regex syntax इस्तेमाल करता है
- POSIX regex backslash और punctuation से भरी structure है
- PCRE POSIX के साथ backward-compatible है और उससे भी ज़्यादा जटिल backslash·punctuation structure को inherit करता है
- Perl 6 ने backward compatibility तोड़कर नई regex syntax पेश की
- सबसे prominent improvement composability है
- कई languages में regex strings को जोड़कर combine किया जाता है
- Raku
/< foo >+/की तरह दूसरे regex को insert करकेfooregex को एक या अधिक बार match करता है, और उसे parent regex में leak नहीं होने देता
- जटिल regex को छोटे और readable हिस्सों में बाँटा जा सकता है
- यही तरीका Raku द्वारा parsing grammars को built-in language feature के रूप में support करने का आधार बनता है
- backward compatibility तोड़ते हुए कई convenience features भी जोड़ी गईं
\d+ % ','1,1,2,1,1,4को match करता है, लेकिन1,या12को match नहीं करता- lookahead और non-capturing group कठिन symbol combinations नहीं हैं
r1 && r2केवल उन strings को match करता है जोr1औरr2दोनों satisfy करती हैं:से backtracking रोकी जा सकती है- whitespace default रूप से ignore होता है, और match pattern में explicitly enable करना पड़ता है
- Raku की regex notation को वास्तविक processing capability से अलग, ऐसी feature के रूप में देखा जा सकता है जो दूसरी languages में भी आ सकती है
Hyperoperators: nested lists तक उतरने वाली generalized mapping
- Hyperoperators का basic form
l>>.methodmapजैसा है, लेकिन sublists के अंदर recursively उतरता है[1, [2, 3], 4]>>.succ[2 [3 4] 5]है
- Raku में
f(list, *args)रूप की function call कोlist.&f(* args)जैसे method form में बदला जा सकता है- इसलिए
>>.generalized mapping operator जैसा काम करता है - Whatever के साथ
[1, [2, 3], 4]>>.&(*+1)की तरह इस्तेमाल किया जा सकता है
- इसलिए
- binary hyperoperator
l1 << op >> l2दोनों lists परopको element-wise apply करता है- छोटी list तब तक repeat होती है जब तक लंबी list खत्म न हो जाए
[1, 2, 3, 4, 5] <<+>> [10, 20][11 22 13 24 15]है<< op<<या>>op>>form केवल तब तक repeat करता है जब तक left या right list खत्म न हो जाए
- single value और nested list पर भी काम करता है
[1, 2, 3, 4, 5] <<+>> 10[11 12 13 14 15]है[1, [2, 3], 4, 5] <<+>> [10, 20][11 [22 23] 14 25]है
- दो hashes के लिए hyperoperator में union·intersection·hash difference पर
opapply करने वाला अलग behavior भी है - Hyperoperator नाम इसलिए पड़ा क्योंकि सभी operations की parallel evaluation होती है
- explicit loops को भी
hyperprefix से parallelize किया जा सकता है
- explicit loops को भी
Pair Syntax: hash की basic unit और concise flag passing
- Pair Raku hash बनाने वाली basic unit है
- hash
key => valuepairs का collection है - pair basic type है और hash pairs का collection है
- hash
- Raku में pair को short form में specify करने वाली बहुत-सी colon syntax हैं
my $x = 3; :$xx => 3है:a<$x>a => "$x"है:a($x)a => 3है:3aa => 3है
- सबसे महत्वपूर्ण shorthand
:keyऔर:!keyहैं- ये क्रमशः
key => True,key => Falseमें map होते हैं - method में flags जोड़ने के concise तरीके के रूप में इस्तेमाल होते हैं
- ये क्रमशः
matchmethod कई colon pairs को flags की तरह लेता है:continue(:$c),:pos(:$p),:global(:$g),:overlap(:$ov)जैसे forms का उपयोग करता है- signature में
:f(:$foo)$fooparameter define करते हुए:falias भी बनाता है - caller
:fया:fooसे same flag set कर सकता है
- Colon pair arguments का order और position flexible है
"abab".match(/../, :g)global matching करता है"abab".match(/../, :g, :ov)overlapping matching करता है"abab".match(:g:ov, /../)की तरह order बदलकर साथ में लिखा जा सकता है"abab".match(:g, /../):ov:2ndकी तरह function call के बाद keyword arguments भी रखे जा सकते हैं
- ऐसी syntax
match(global=True, overlap=True)की तुलना में method options को कहीं ज़्यादा short form में specify करने देती है
Slangs, RakuAST, Rakudo Star
- Slangs Raku syntax बदलने वाली feature है
- loop syntax modify करने, identifiers बदलने, actor जोड़ने, DNA sequence जोड़ने जैसे कामों में इस्तेमाल हो सकती है
- उदाहरणों में Slang::Otherwise, Slang::Piersing, OO::Actors, BioInfo आते हैं
- RakuAST Raku expressions को Raku के अंदर AST के रूप में parse करने वाली feature है
Q/my $x; $x++/.ASTvariable declaration और postfix increment operation कोRakuAST::StatementListform में दिखाता हैQ/my $x; put $x/.AST.DEPARSE("NL")की तरह Raku code को किसी दूसरी language-style notation में output करने का example है
- Raku में Rakudo Star installer/distribution है
- यह distribution चुने हुए third-party modules को pre-install करके देता है
- यह बड़े standard library की maintenance burden और user को ecosystem में suitable package खुद ढूँढने की burden के बीच का compromise जैसा है
1 टिप्पणियां
Hacker News टिप्पणियां
पहले यहां बताई गई composable regex सुविधा जैसी चीज़ मैंने JavaScript के लिए अलग से लागू की थी, और कई साल बाद भी यह उन libraries में से एक है जिसे मैं दूसरे projects में सबसे ज्यादा साथ ले जाता हूं
इससे भाषा के अंदर first-class parser होने जैसा एहसास थोड़ा और करीब आता है, और उदाहरण के तौर पर इसका उपयोग करके regex से media type parsing लागू किया गया है: https://runkit.com/tolmasky/media-type-parsing-with-template...
npm का
templated-regular-expression, GitHub: https://github.com/tolmasky/templated-regular-expressionबेशक programming languages में असली parser होना चाहिए और regex को parser की तरह इस्तेमाल नहीं करना चाहिए, लेकिन अगर वैसे भी regex इस्तेमाल करना है, तो उसे छोटे-छोटे टुकड़ों में बांट पाना सच में बहुत अच्छा है
Raku के regex grammar के साथ मिलकर कहीं ज्यादा शक्तिशाली हो जाते हैं, और अच्छी तरह लिखे जाएं तो किसी भी “असली parser” से ज्यादा समझने में आसान होते हैं। Raku को किसी सामान्य parser से parse करने के लिए parsing के दौरान parser में items जोड़ने और हटाने की क्षमता चाहिए; Raku का parser इसे वर्तमान grammar को subclass करके, मौजूदा lexical scope के अंदर items जोड़ने-हटाने और scope खत्म होने पर पिछली grammar पर लौटने के तरीके से संभालता है
Raku में regex code लिखने की एक और grammar है, और बुनियादी grammar से इसका व्यवहार बस थोड़ा अलग है; इसमें parameters और variables हो सकते हैं। अगर regex grammar किसी काम के लिए ठीक न बैठे, तो सामान्य Raku grammar को बीच में डालकर जरूरी काम किया जा सकता है और फिर regex grammar पर वापस लौटा जा सकता है
उदाहरण के लिए, एक या अधिक
Aके बाद उतनी ही संख्या मेंBऔर उतनी ही संख्या मेंCmatch करना भी संभव है। ज्यादातर regex grammars में समान संख्या केAऔरBmatch करने के लिए बीच में recursion चाहिए, लेकिन ऐसा करने परCको भी उसी तरह संभालना मुश्किल हो जाता है और पढ़ना भी काफी कठिन हो जाता है। Raku का तरीका backtracking या recursion नहीं मांगता, इसलिए काफी तेज चल सकता हैgrammar में बांधने पर पूरा parse tree मिलता है; grammar के बिना भी संभव है, लेकिन grammar इस्तेमाल करना आसान रहता है। वास्तविक parser के उदाहरण के तौर पर JSON::TINY::Grammar अक्सर सुझाया जाता है: https://github.com/moritz/json/blob/master/lib/JSON/Tiny/Gra...
सच कहूं तो “असली parser” design का बड़ा हिस्सा शुरुआती computers की सीमित RAM से निकला एक byproduct लगता है। अलग tokenization step का मकसद source code द्वारा ली जाने वाली RAM घटाना था, ताकि बाद के semantic analysis और compilation के लिए memory बची रहे; मुझे नहीं लगता कि वह बाद के steps को इतना ज्यादा सरल बनाता है। ऊपर वाला JSON::Tiny module parsing के दौरान action class के जरिए native Raku data structures बनाता है, इसलिए वह parsing करते-करते साथ ही compile भी कर रहा होता है
Production में Raku इस्तेमाल कर रहा हूं। text processing के लिए यह सबसे अच्छी भाषा है, और parser बनाने का अनुभव बहुत शानदार है
हैरानी है कि यह LLM text pipelines बनाने की top-tier भाषा नहीं है
वाह। जिस दिन मुझे Raku codebase maintain करना पड़े, उससे पहले industry छोड़ देने का मन हो रहा है
शुरुआती Raku books देखने पर कई जगह यह Python पर C-family syntax चढ़ा देने जैसा महसूस होता है। syntax braces-centric है, लेकिन usability, built-in data structures और object-oriented features सब high-level हैं
अगर आप कोई दूसरी high-level scripting language जानते हैं, तो मिलती-जुलती script का Raku code काफी आसानी से पढ़ सकेंगे। रोजमर्रा के code में ज्यादातर लोग सचमुच अजीब features इस्तेमाल करेंगे, ऐसा नहीं लगता; Raku ज्यादा flexible है, लेकिन आम तौर पर code पेचीदा नहीं दिखता
Raku में keyword arguments को shorthand में define करने की सुविधा—जैसे
:global(:$g)—याTruevalue मानकरmatch(/foo/, :g)की तरह global regex match call करने की क्षमता में भी यह दिखता है। Perl में भी ऐसी बहुत सी चीजें हैं, और वे सब तेज और मजेदार तरीके से लिखने के लिए हैं, लेकिन beginners के लिए कम readable होती हैंअब यह generation gap बनने वाला है। पुराने programmers की पूरी पीढ़ी को लग सकता है कि मौजूदा पीढ़ी के लिए सामान्य working environment में उनकी जगह छिन गई है
कुछ features आधे-अधूरे परिचित लगते हैं। Hyper recursion-schemes वाली किसी चीज़ का ज्यादा improvised version लगता है, और यहां दिखा
*कुछ हद तक Scala के_जैसा है_lambdas में इस्तेमाल करने के लिए अच्छा लगता है, इसलिए काश हर भाषा कुछ वैसा अपना ले> (2, 30, 4, 50).map(* + *) returns (32, 45)कोreturns (32, 54)नहीं होना चाहिए? क्योंकि दूसरा term 4+50 होगाशायद यह कुछ देशों में English के fifty-four की बजाय vierenvijftig जैसे “four and fifty” कहने के तरीके से आया heading translation result हो सकता है
(32 54)return करता है। लगता है लेखक से typo हो गयातो क्या अब Perl, APL परिवार की भाषाओं की ओर जाने वाली gateway drug है?
उदाहरण के लिए, reduce meta operator
[ ]को infix+के साथ इस्तेमाल करके “सबका योग” किया जा सकता है:[+] 1, 2, 3Raku में अभी भी speed एक बड़ी समस्या है। regex से log file parse करना Perl की ताकत है, लेकिन latest Raku भी startup time हटाने के बाद Python 3.13 से 6.5 गुना ज्यादा समय लेता है
(2,4,8...*)[17]का262144होना सचमुच चौंकाने वाला थाWhateverको छोड़ दें, तो Perl6/Raku के बाद की नई बात शायद lazy evaluation की तरफ़ है(1,3,9...*)[4,5]से(81 243)मिलता है, और(1,3,9...*)[(1..3)]से(3 9 27)मिलता हैnesting भी संभव है, इसलिए
(1,2,4...*)[(1,2,4...*)[1,2,3]]जैसा expression भी चल सकता हैयानी Raku के दिलचस्प features चुनकर कवर किए गए हैं
मेरी नज़र में सबसे महत्वपूर्ण Raku features command-line interface और grammar हैं
command-line interface support एक आम feature है, और उदाहरण के लिए
docoptimplementations और adoption cases मौजूद हैं। लेकिन Raku में यह feature built-in है और इस्तेमाल में अच्छा हैदूसरी ओर grammar एक दुर्लभ feature है, क्योंकि programming language first-class component के रूप में grammar देती है और object-oriented programming से grammar बनाने और compose करने देती है
मैं इस project को कई सालों से देख रहा हूँ और यह दिलचस्प तो है, लेकिन सचमुच अफ़सोस है कि Perl 6 इस आईने की दुनिया की यात्रा में बहुत ज़्यादा भटक गया लगता है