1 पॉइंट द्वारा GN⁺ 2024-11-14 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • 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|10 any(2, 10) बन जाता है
    • 2&10 + 3 all(5, 13) बन जाता है
    • (1&2) + (10^20) all(one(11, 21), one(12, 22)) की तरह combine होता है
  • Junctions का मुख्य उपयोग all, any की तरह boolean formulas व्यक्त करना है
    • junction को destructure करने का कोई तरीका नहीं है
    • असल में इस्तेमाल करने के लिए पहले उसे boolean में fold करना पड़ता है
  • so junction को boolean में force-convert करता है
    • so (1&2) + (10^20) < 15 True है
    • so (1&2) + (10^20) > 0 False है
  • Raku का list.all arguments लेने वाला method नहीं, बल्कि list को junction में बदलने वाला no-argument method है
    • <1 2 3>.all all(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 है

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 करके foo regex को एक या अधिक बार 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>>.method map जैसा है, लेकिन 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 पर op apply करने वाला अलग behavior भी है
  • Hyperoperator नाम इसलिए पड़ा क्योंकि सभी operations की parallel evaluation होती है
    • explicit loops को भी hyper prefix से parallelize किया जा सकता है

Pair Syntax: hash की basic unit और concise flag passing

  • Pair Raku hash बनाने वाली basic unit है
    • hash key => value pairs का collection है
    • pair basic type है और hash pairs का collection है
  • Raku में pair को short form में specify करने वाली बहुत-सी colon syntax हैं
    • my $x = 3; :$x x => 3 है
    • :a<$x> a => "$x" है
    • :a($x) a => 3 है
    • :3a a => 3 है
  • सबसे महत्वपूर्ण shorthand :key और :!key हैं
    • ये क्रमशः key => True, key => False में map होते हैं
    • method में flags जोड़ने के concise तरीके के रूप में इस्तेमाल होते हैं
  • match method कई colon pairs को flags की तरह लेता है
    • :continue(:$c), :pos(:$p), :global(:$g), :overlap(:$ov) जैसे forms का उपयोग करता है
    • signature में :f(:$foo) $foo parameter define करते हुए :f alias भी बनाता है
    • 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++/.AST variable declaration और postfix increment operation को RakuAST::StatementList form में दिखाता है
    • 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 टिप्पणियां

 
GN⁺ 2024-11-14
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 इस्तेमाल करना है, तो उसे छोटे-छोटे टुकड़ों में बांट पाना सच में बहुत अच्छा है

    • “असली parser” Raku को parse करने के लिए पर्याप्त शक्तिशाली नहीं है
      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 और उतनी ही संख्या में C match करना भी संभव है। ज्यादातर regex grammars में समान संख्या के A और B match करने के लिए बीच में 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 से HTTPS API call करने और कोई specific value return होने तक polling करने का अच्छा example पता है?
    • क्या आप Raku के LLM packages इस्तेमाल कर रहे हैं? अगर हां, तो कौन से?
  • वाह। जिस दिन मुझे Raku codebase maintain करना पड़े, उससे पहले industry छोड़ देने का मन हो रहा है

    • मजेदार बात यह है कि वह blog post पढ़ने के बाद मेरा मन हुआ कि नौकरी छोड़कर Raku team को ढूंढूं और उनके साथ काम करूं। शायद मैं अभी बहुत भोला हूं :)
    • अगर आपने सामान्य Raku code नहीं देखा है, तो लेख देखकर ऐसी प्रतिक्रिया आना समझ में आता है
      शुरुआती 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 पेचीदा नहीं दिखता
    • Perl जैसा ही है। कोई इसे maintain नहीं करना चाहता, लेकिन इस्तेमाल करना सच में मजेदार है। इसकी expressiveness बहुत बड़ी है
      Raku में keyword arguments को shorthand में define करने की सुविधा—जैसे :global(:$g)—या True value मानकर match(/foo/, :g) की तरह global regex match call करने की क्षमता में भी यह दिखता है। Perl में भी ऐसी बहुत सी चीजें हैं, और वे सब तेज और मजेदार तरीके से लिखने के लिए हैं, लेकिन beginners के लिए कम readable होती हैं
    • अजीब है कि लोग AI-assisted codebases maintain करने के बारे में भी ऐसी ही बातें करते हैं
      अब यह generation gap बनने वाला है। पुराने programmers की पूरी पीढ़ी को लग सकता है कि मौजूदा पीढ़ी के लिए सामान्य working environment में उनकी जगह छिन गई है
    • मुझे नहीं लगता कि Raku “industry” के लिए बनाई गई भाषा है
  • कुछ 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 हो सकता है

    • rakudo में check किया तो असल में यह (32 54) return करता है। लगता है लेखक से typo हो गया
  • तो क्या अब Perl, APL परिवार की भाषाओं की ओर जाने वाली gateway drug है?

    • सही है। ऊपर से लेख में meta operators को भी कवर नहीं किया गया
      उदाहरण के लिए, reduce meta operator [ ] को infix + के साथ इस्तेमाल करके “सबका योग” किया जा सकता है: [+] 1, 2, 3
  • Raku में अभी भी speed एक बड़ी समस्या है। regex से log file parse करना Perl की ताकत है, लेकिन latest Raku भी startup time हटाने के बाद Python 3.13 से 6.5 गुना ज्यादा समय लेता है

    • उदाहरण भी साथ में देना चाहिए। मेरे अनुभव में Raku कुछ चीज़ों में तेज़ भी है और कुछ में धीमा भी, इसलिए यह देखे बिना कि किस चीज़ में धीमा है, सिर्फ़ “Raku, Python 3.13 से 6.5 गुना ज्यादा समय लेता है” कहना खास मायने नहीं रखता
  • (2,4,8...*)[17] का 262144 होना सचमुच चौंकाने वाला था

    • मेरे दिमाग में तुरंत “भयानक” शब्द आया, और फिर “भयानक परिणाम” और halting problem याद आए, लेकिन हर किसी की पसंद अलग हो सकती है
    • increment detection Perl6 में बहुत पहले से था, इसलिए यह नया feature नहीं है
      Whatever को छोड़ दें, तो Perl6/Raku के बाद की नई बात शायद lazy evaluation की तरफ़ है
    • यह काफ़ी consistent है
      (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 है, और उदाहरण के लिए docopt implementations और adoption cases मौजूद हैं। लेकिन Raku में यह feature built-in है और इस्तेमाल में अच्छा है
    दूसरी ओर grammar एक दुर्लभ feature है, क्योंकि programming language first-class component के रूप में grammar देती है और object-oriented programming से grammar बनाने और compose करने देती है

  • मैं इस project को कई सालों से देख रहा हूँ और यह दिलचस्प तो है, लेकिन सचमुच अफ़सोस है कि Perl 6 इस आईने की दुनिया की यात्रा में बहुत ज़्यादा भटक गया लगता है

    • जिज्ञासा है कि Patrick Michaud आजकल कैसे हैं और क्या कर रहे हैं