Raku (fost Perl 6) | |
---|---|
Clasa de limba | Multi-paradigma |
Aparut in | Dezvoltarea continuă din anul 2000. Prima lansare a avut loc pe 25 decembrie 2015 |
Autor | Larry Wall |
Dezvoltator | Larry Wall și Audrey Tan |
Extensie de fișier | .raku, .rakumod, .rakudoc, .rakutestsau.t |
Eliberare | 6.d (24 februarie 2020 ) |
Tip sistem | dinamic, static |
A fost influențat |
haskell , JavaScript , Perl , Ruby , Smalltalk , J |
influențat | Perl , Haskell , AntLang |
Licență | Licență publică generală GNU , Licență artistică |
Site-ul web | raku.org |
OS | multiplatformă |
Raku (din japoneză 楽土, pron. rakudo - Paradis , [1] [2] și din 楽, pron. raku - fericire, ușurință, sukha [3] [4] ) este un limbaj de programare din familia limbajelor de tip Perl . O revizuire majoră atât a designului, cât și a implementării limbajului Perl, rupând compatibilitatea cu acesta, deși modul de compatibilitate ar fi trebuit să existe încă până în 2010. [5]
La fel ca limbajul Perl, Raku lasă multă libertate programatorilor . Vă permite în continuare să vă exprimați concis, inclusiv scrierea de versuri, dar simplifică și scrierea de programe mari, datorită tastării statice și suportului OOP îmbunătățit .
Fostul nume al lui Raku era Perl 6. [6] De mulți ani au existat glume în comunitatea Perl despre data lansării. La întrebarea „când va fi lansat Perl 6”, răspunsul obișnuit a fost „de Crăciun”, dar fără un an. [7] [8] În 2015, adică după cincisprezece ani de așteptare, a fost anunțată în sfârșit versiunea așa-numită „Crăciun”. [9] [10] [11]
În Perl 6, am decis că este mai bine să reparăm limba decât să reparăm utilizatorul.Larry Wall [12]
Dezvoltarea lui Perl 6 a fost anunțată pentru prima dată de Larry Wall pe 19 iulie 2000, a patra zi a Conferinței Perl din acel an, [13] în discursul său State of the Onion . [14] La acea vreme, prioritățile erau: eliminarea „negilor istorici” din limbă; „lucrurile simple trebuie să rămână simple, lucrurile complexe trebuie să devină mai simple, iar lucrurile imposibile trebuie să devină complexe”; curățarea generală a designului intern și API . Procesul a început cu o serie de RFC -uri . Acest proces a fost deschis tuturor participanților și niciun aspect al limbii nu a fost lăsat închis pentru schimbare. [cincisprezece]
Au fost primite 361 de cereri, toate examinate de Wall. Apoi a început procesul de a scrie mai multe „Apocalipse”, un termen creștin care înseamnă „dezvăluirea veștilor bune oamenilor buni”. [16] Deși scopul inițial a fost de a scrie o Apocalipsă pentru fiecare capitol din cartea en:Programming Perl , a devenit evident că, pe măsură ce fiecare Apocalipsă a fost scrisă, Apocalipsele anterioare au fost anulate de modificările ulterioare. Din acest motiv, a fost publicat un set de Sinopse, fiecare referindu-se la o singură Apocalipsă, dar incluzând corecții din noile Apocalipse. Astăzi, specificația Raku este condusă de suita de teste „prăjire”, [17] în timp ce Sinopzele sunt păstrate ca referință istorică. [optsprezece]
Există și o serie de Exegeze scrise de Damian Conway care explică conținutul fiecărei Apocalipse din punct de vedere al utilizării practice. Fiecare exegeză constă din exemple de cod cu o discuție despre utilizarea și semnificația lor. [19]
Scopul principal pe care Wall l-a propus în discursul său inițial a fost eliminarea „negilor istorici”. Acestea au inclus confuzie în simbolurile matricelor și hash-urilor, ambiguitatea în funcții select, probleme cu utilizarea descriptorilor de fișiere [20] (fără punctuație [21] ). Wall a menționat și multe alte probleme în discursul său despre care programatorii Perl le discută de ani de zile.
Consecința acestor obiective a fost pierderea compatibilității cu retrocompatibilitatea. Deoarece compatibilitatea inversă este de obicei implicită atunci când software-ul este îmbunătățit, modificările din Perl 6 care îl distrug ar fi trebuit să fie menționate în mod explicit. Treptat, diferența dintre Perl 5 și Perl 6 a devenit atât de mare încât Perl 6 a fost redenumit Raku pe 12 octombrie 2019 . [6]
De-a lungul anilor, vectorul de dezvoltare al lui Raku s-a schimbat de mai multe ori. Introducerea conceptelor din Python și Ruby a fost o influență timpurie. [22] [23] [24] În plus, Pugs, primul interpret Raku, este scris în limbajul funcțional Haskell , iar multe elemente de programare funcțională au fost absorbite de echipa de dezvoltare Raku. [25] [26]
Mascota limbii este insecta Camellia. [27] Numele său este o referire la emblema limbajului Perl, cămila ("Camel"), iar forma sa, în tradiția comunității Perl iubitoare de jocuri de cuvinte , ecou cuvântul " bug ". Modelele în spirală înscrise în aripile sale asemănătoare unui fluture amintesc de personajele „P6”, iar strabisul divergent este un joc de cuvinte deliberat cu „Wall-eyed”. [28]
Unul dintre scopurile designului logo-ului plin de viață și colorat a fost acela de a descuraja misoginia în comunitate și de a permite oamenilor cu „credințe masculine” să-și arate latura sensibilă. [29]
Rakudo este cea mai dezvoltată implementare, [30] ceea ce nu o face versiunea oficială a limbii, așa cum limbajul nu este definit de implementare, ci de suita de teste. [31]
Rakudo vă permite să executați cod [32] în mașinile virtuale MoarVM , JVM și Node.js. [33] MoarVM este o mașină virtuală construită special pentru Rakudo și compilatorul NQP. [34] [35] Compilatorul NQP (Not Quite Perl 6 ) implementează un subset al limbajului care include reguli Raku pentru analizarea codului sursă, manipularea arborelui de sintaxă abstractă și generarea codului specific backend-ului . O mare parte din Rakudo este scrisă în Raku și NQP. Rakudo nu este un compilator autonom și nu există planuri de promovare a compilatorului în acest moment.
După versiunea „2015.02”, Rakudo a renunțat la suportul pentru mașina virtuală Parrot [36] (predecesorul MoarVM), bazată pe presupunerea greșită că Perl 6 ar fi similar cu Perl 5. [37] [38]
Prima implementare a lui Raku a fost Pugs [39] , un interpret și compilator scris în Haskell . A fost cea mai avansată implementare, totuși au fost făcute doar remedieri minime din 2007 pentru a ține pasul cu noile versiuni de GHC , iar din noiembrie 2014, Pugs nu este acceptat. [40] În august 2006, Yichun Zhang a împărțit fișierele de testare Pugs în fragmente, atașându-le paragrafele Sinapselor corespunzătoare, [41] [42] iar în ianuarie 2008, aceste teste au fost integrate în testele oficiale ale limbii („prăjire). ”). [43] [44] În februarie 2015, comunitatea a declarat că testele de limbă sunt o specificație. [45]
Raku și Perl sunt fundamental diferiți, deși intenția a fost să-l păstreze pe Raku ca Perl. Majoritatea modificărilor sunt menite să normalizeze limbajul, astfel încât să fie mai ușor de înțeles atât pentru programatorii începători, cât și pentru cei experimentați și pentru a face „lucrurile simple mai ușoare și cele complexe mai posibile”.
Principala diferență non-tehnică este că Raku a început ca o specificație. [31] Aceasta înseamnă că Raku poate fi reimplementat dacă este necesar și, de asemenea, că programatorii nu trebuie să citească codul sursă pentru a obține controlul deplin asupra oricăreia dintre caracteristicile sale. În cazul limbajului Perl, documentația oficială descrie doar comportamentul interpretului curent. Orice discrepanțe găsite între documentație și implementare pot duce la schimbarea fie a uneia, fie a celeilalte, ceea ce este forța motrice din spatele dezvoltării și îmbunătățirii continue a versiunilor Perl.
În Raku, sistemul de tip dinamic a fost completat cu tipuri statice . [46] De exemplu:
my Int $i = 0 ; Șobolanul meu $r = 3.142 ; my Str $s = "Bună, lume" ;Cu toate acestea, tipurile statice rămân opționale, astfel încât programatorii pot face majoritatea lucrurilor fără a specifica în mod explicit tipurile.
my $i = "25" + 10 ; # $i este 35În Perl, subrutinele nu au parametri formali , deși o simplă verificare a numărului și a tipurilor de parametri este posibilă folosind prototipuri de subrutine. [47] În schimb, parametrii efectivi trecuți prin referință sunt ascunși în spatele elementelor matricei @_din corpul subrutinei.
Parametrii formali reali apar în Raku. [48] De exemplu:
sub face_ceva ( Str $lucru , Int $altul ) { ... }La fel ca în Perl, în Raku parametrii sunt trecuți prin referință, dar implicit în Raku sunt constanți , adică valorile lor nu pot fi modificate. Ele pot fi declarate în mod explicit pentru a permite modificarea valorii inițiale ( is rw) sau ca copii ( is copy), ceea ce este echivalent cu trecerea după valoare.
Modalități de a trece parametriiExistă trei moduri de a transmite parametri în Raku: pozițional, cu nume și slurpy .
Parametrii de poziție sunt doar o listă ordonată, ca în majoritatea limbajelor de programare. Chiar și ele pot fi transmise într-o ordine arbitrară, atâta timp cât le sunt date numele. Parametrii care pot fi trecuți numai după nume sunt notați printr-un simbol :înaintea simbolului parametrului formal. Squishing parametrii este o modalitate de a crea funcții variabile în Raku. Ele sunt indicate printr-un simbol *înaintea sigilului parametrului formal. Hash-ul slurpy va captura parametrii numiți nemenționați în declarația subrutinei, iar matricea slurpy va captura parametrii actuali de poziție ulterioare.
În exemplul următor, toate cele trei metode sunt prezente, inclusiv o matrice slurpy.
sub o anumită funcție ( $a , $b , : $c , : $d , * @e ) { ... } o anumită funcție ( 1 , 2 , : d ( 3 ), 4 , 5 , 6 ); # $a=1, $b=2, $d=3, @e=(4,5,6)Parametrii de poziție sunt necesari în mod implicit, cu excepția cazului în care numele parametrului este urmat de un semn de întrebare. Parametrii impliciti numiți, pe de altă parte, sunt opționali, cu excepția cazului în care numele este urmat de un semn de exclamare. Parametrii squishy sunt întotdeauna opționali.
Blocuri și închideriParametrii pot fi, de asemenea, transferați oricăror blocuri de cod care se comportă ca închideri . În special, de exemplu, corpurile de cicluri forsunt whileînchideri. În exemplul următor, bucla preia trei elemente din listă odată și le transmite blocului ca variabile $ași . [49]$b$c
pentru @list -> $a , $b , $c { ... }Aceasta se numește „subpunct” sau „bloc ascuțit”, iar săgeata din el se comportă oarecum ca un cuvânt cheie sub, introducând o închidere anonimă (sau o subrutină anonimă în terminologia Perl). [48]
În Perl, simbolurile (semnele de punctuație care apar înaintea numelor de variabile) se modifică în funcție de modul în care este utilizată variabila .
# Cod Perl my @ array = ('a', 'b', 'c'); elementul meu $ = $ array[1]; # returnează „b”, my @extract = @array [ 1, 2]; # returnează („b”, „c”) elementul meu $ = @array [1]; # returnează „b” cu avertisment (din 5.10)În Raku, simbolurile sunt invariante: atât o matrice, cât și un element de matrice vor avea același simbol. [46]
# Cod Raku my @ array = 'a', 'b', 'c'; elementul meu $ = @array [1]; # $element este scris „b” my @extract = @array [ 1]; # @extract este scris ('b') my @extract = @array [ 1, 2]; # @extract este scris ('b', 'c')Variabilitatea simbolurilor în Perl este inspirată de convenția numerelor din engleză și din multe alte limbi naturale .
„ Este un măr”. # $a este adevărat „ Aceste mere”. # @un adevar „ Acesta este al treilea măr”. # $a[3] este adevărat „ Aceștia sunt al treilea măr”. # @a[3] nu este corectCu toate acestea, acest concept este rupt atunci când intră în joc referințele, deoarece se pot referi la structurile de date în timp ce sunt scalari. Astfel, lucrul cu structuri de date imbricate poate necesita ca atât singularul, cât și pluralul să fie exprimate în același termen:
# Cod Perl: obținerea unui tablou dintr-un element hash. # Acest hash stochează hashuri care conțin matrice. my @trans_verbs = @ { $dictionar { 'verb' }{ 'tranzitiv' } };Astfel de construcții nu au analogi în limbajele naturale comune, ceea ce provoacă o sarcină cognitivă mare la scrierea codului. Același cod Raku:
# Cod Raku: obținerea unei matrice dintr-un element hash. # Acest hash stochează hashuri care conțin matrice. my @trans_verbs = %dictionary<verb><tranzitiv><> ;În limbajul Perl, programarea orientată pe obiecte este suportată printr-o funcție care transformă orice variabilă într-un obiect al unei anumite clase, din care metodele declarate în clasă blessdevin disponibile pentru apel . [cincizeci]
Deși extrem de puternic, acest mecanism în același timp face dificilă descrierea chiar și a celor mai elementare OOP - obiecte simple asemănătoare structurii cu proceduri asociate. De asemenea, deoarece Perl nu face ipoteze despre modelul obiect, apelurile de metodă nu pot fi optimizate de compilator.
Raku păstrează metoda de nivel scăzut bless, dar oferă și un model de obiect mai restrictiv pentru cazurile de utilizare obișnuite. [51] [52] De exemplu, o clasă care încapsulează un punct într-un sistem de coordonate carteziene poate fi definită după cum urmează:
clasa Punctul este rw { are $.x ; are $.y ; metoda distanta ( Punctul $p ) { sqrt (( $!x - $p . x ) ** 2 + ( $!y - $p . y ) ** 2 ) } metoda distanta la centru { self . distanta: Punct . nou ( x => 0 , y => 0 ) } } my $point = Punct . nou ( x => 1,2 , y => - 3,7 ); spune "Poziția punctului: (" , $punct . x , ', ' , $punct . y , ')' ; # Poziția punctului: (1,2, -3,7) # Schimbați x și y (folosind metodele „x” și „y”): $point . x = 3 ; $punct . y = 4 ; spune "Poziția punctului: (" , $punct . x , ', ' , $punct . y , ')' ; # Poziția punctului: (3, 4) my $altul-punct = Punct . nou ( x => - 5 , y => 10 ); $punct . distanta ( $alt-punct ); # => 10 $punct . distanta pana la centru ; # => 5În Perl, metodele sunt invocate cu o săgeată: $object->method(). Raku folosește un punct în loc de o săgeată ca multe alte limbi (cum ar fi Java și Python).
În terminologia Raku, $.xse numește un atribut. Metoda folosită pentru a accesa un atribut se numește accesor [53] (din engleză access - access). Este creat automat (când un atribut este declarat cu un punct [54] ) și este numit la fel ca și atributul. Funcționează ca un getter și atunci când o clasă sau un atribut is rwpreia proprietățile unui setter și poate fi folosit în partea stângă a unei sarcini. În loc de accesorii automati, programatorul își poate defini propriile metode personalizate. De asemenea, în corpul clasei, toate atributele, indiferent de modul în care sunt declarate, pot fi accesate direct folosind $!.
Moștenire, roluri și claseMoștenirea este o tehnică în care obiectele sau tipurile reutiliza logica sau definițiile de la alte obiecte sau tipuri. De exemplu, un programator poate crea un tip standard cu un atribut opțional. În limbaje precum Java, moștenirea este asigurată de clase, care pot fi subclase ale altor clase existente.
Raku oferă, de asemenea, moștenire prin clase, similar claselor din alte limbaje de programare, precum și prin roluri.
Rolurile din Raku preiau funcția de interfețe în Java, mixin în Ruby, trăsături [55] în PHP și Squeak (un dialect al limbajului Smalltalk ). Sunt similare cu clasele, dar oferă un mecanism de compunere mai sigur decât moștenirea, care previne conflictele de nume de atribute și metode. [56] [57] Rolurile nu sunt incluse într-un lanț de moștenire. Rolurile se referă la sistemul de tip nominal (vezi en:Sistem de tip nominal ), nu la sistemul de tip structural, care este folosit, de exemplu, în Go . Ele furnizează nume semantice pentru seturi de comportamente și stări. Diferența fundamentală dintre roluri și clase este că rolurile nu instanțiază obiecte. [58]
Deși rolurile sunt diferite de clase, este posibil să se scrie cod care creează un obiect dintr-un rol. Încercarea de a utiliza un rol pentru a crea un obiect va avea ca rezultat crearea unei clase cu același nume. Documentația Raku numește acest mecanism joc de cuvinte automate. clasa generată este un joc de cuvinte. [59]
În esență, rolurile sunt pachete de atribute și metode potențial abstracte care pot fi adăugate la o clasă fără a utiliza moștenirea. Un rol poate fi adăugat chiar și unui singur obiect. În ultimul caz, Raku va crea o subclasă anonimă, îi va adăuga un rol și va înlocui clasa obiectului cu acea subclasă anonimă.
De exemplu, un câine este un mamifer , deoarece câinii moștenesc anumite trăsături de la mamifere, cum ar fi glandele mamare și, prin strămoșii lor vertebrați , coloana vertebrală . Pe de altă parte, câinii pot avea diferite tipuri de comportament care se pot schimba în timp. De exemplu, un câine poate fi domestic, vagabond, poate fi ghid . Aceste seturi de comportamente suplimentare pot fi adăugate câinelui. Le puteți descrie în așa fel încât să le puteți aplica altor animale. De exemplu, o pisică poate fi domestică și vagabondă. Câinele și pisica sunt distincte unul de celălalt, dar rămân în categoria generală a mamiferelor. Deci, Млекопитающее este o clasă Собакаși Кошка sunt clase moștenite de la un mamifer. Dar comportamentele de mai sus sunt roluri care pot fi adăugate la clase sau obiecte create din clase.
clasa Mamifer este vertebrat { ... } clasa Câinele este mamifer { ... } rol Pet { ... } rol fără adăpost { ... } ghid de rol { ... }Rolurile sunt adăugate la clase și obiecte folosind does. Pentru moștenire, se folosește cuvântul cheie is. Aceste cuvinte reflectă o diferență în sensul acestor trăsături de limbaj: atașarea unui rol conferă unei clase comportamentul unui rol, dar nu înseamnă că clasa devine literalmente aceeași cu acel rol.
clasa Câinele Ghid este Câinele Ghid are Câine Ghid { ... } # Subclasa atașează un rol. my $dog = Câine . nou (); $dog does Guide Dog ; # Obiectul atașează rolul.Atât rolurile, cât și clasele sunt tipuri. Un rol poate fi utilizat într-o declarație de variabilă. De exemplu, un rol Незрячийpoate conține un atribut de tip Поводырь, care ar putea fi un câine ghid, un cal ghid, o persoană ghid sau chiar o mașină ghid.
clasa Om { are Câine $câine ; # Poate conține orice fel de câine - ... # nu contează dacă este un câine ghid sau nu. } rol Blind { are Ghid $ghid ; # Poate conține orice obiect cu rolul de ... # Ghid - indiferent dacă este un Câine sau nu. }Expresiile regulate și manipularea șirurilor au fost întotdeauna una dintre caracteristicile definitorii ale Perl. [60] Deoarece modelele lui Perl au depășit expresiile regulate la un moment dat, [61] documentația Raku se referă la ele pur și simplu ca regexe , distanțandu-se de definiția formală a expresiilor regulate.
Raku extinde setul de caracteristici Perl în jurul expresiilor regulate prin imbricarea acestora într-un cadru mai larg pentru construirea de analizoare numite reguli . [62] Regulile oferă capabilități de analizare sensibile la context (cum ar fi predicatul sintactic din PEG și ANTLR ) și se comportă ca niște închideri cu privire la sfera lor lexicală . [63] Regulile sunt introduse folosind cuvântul cheie rule, care este similar în utilizare cu definirea unei subrutine. Regulile anonime pot fi introduse folosind cuvântul cheie regex(sau ) rxsau pot fi descrise ca expresii regulate în Perl folosind operatorii m(potrivire) sau s(înlocuire).
În Apocalypse 5 , Larry Wall enumeră 20 de probleme cu „cultura regex” actuală. Printre altele, expresiile regulate Perl erau „prea compacte și „drăguțe””, „se bazau prea mult pe prea puține caractere speciale”, aveau „suport slab pentru capturarea numelui”, „suport slab pentru gramatică” și „integrare slabă a limbajului”. .". [64]
Unele constructe Perl din Raku au fost modificate și optimizate pentru alte expresii sintactice. De exemplu, parantezele, care erau necesare în instrucțiunile de ordine de execuție , sunt acum opționale. [49]
dacă este adevărat () { pentru @array { ... } }Operatorul ,(virgulă) este acum un constructor de listă, astfel încât parantezele în jurul listelor nu sunt necesare.
@matrice = 1 , 2 , 3 , 4 ;Raku permite următoarele expresii:
if 20 <= $temperature <= 25 { spune "Temperatura din camera este intre 20 si 25 de grade!" }Aceasta este percepută ca comparații secvențiale de la stânga la dreapta, urmate de o unire printr-un AND logic .
Raku folosește o tehnică de evaluare a listelor leneșe , similară cu unele limbaje funcționale , cum ar fi Haskell : [65]
@integers = 0 .. inf ; # numere întregi de la zero la infinitAcest cod nu va genera o eroare în încercarea de a pune o listă infinită într-o matrice @integersși nu se va bloca încercând să mărească lista la infinit dacă este solicitat un număr finit de elemente.
Acest lucru simplifică multe sarcini comune în Raku, inclusiv operațiunile I/O, transformările listelor și trecerea parametrilor.
De asemenea, este posibil să creați liste leneșe folosind cuvintele cheie gatherși take. Sunt similare cu generatoarele din Icon și Python .
my $squares = leneș adună pentru 0 .. Inf { take $_ * $_ ; };Iată $squareso listă infinită de pătrate de numere naturale (inclusiv zero), dar din cauza naturii leneșe a acestei liste, elementele sunt evaluate doar atunci când sunt accesate. [66]
Raku introduce conceptul de joncțiuni [67] ( ing. joncțiune - conexiune, intersecție; în Raku acest termen este legat și de conjuncție și disjuncție [65] ). Este o suprapunere a mai multor valori. [65] În forma sa cea mai simplă, o intersecție este creată de operatorii de intersecție :
# Un exemplu de trecere de tip | ("oricare"): my $culoare = 'alb' ; cu excepția cazului în care $culoare eq 'alb' | „negru” | 'gri' { die "Imprimarea în această culoare nu este acceptată.\n" ; } # Un exemplu de cruce ca & ("toate"): my $parola = 'secret!123' ; if $parolă ~~ /<:alpha>/ & / <:digit> / & / <:punct> / { spune „Parola ta este suficient de puternică”. ; }Operatorul |exprimă o valoare egală fie cu argumentul stânga sau dreapta, operatorul & - atât stânga cât și dreapta. Aceste valori pot fi folosite în cod oriunde se presupune că o valoare este semantică. Orice operațiuni cu trecere acționează simultan asupra tuturor componentelor sale, iar rezultatul este combinat prin operatorul acestei traversări. Da, se ("apple"|"banana") ~ "s"va întoarce "apples"|"bananas". Totuși, într-un context boolean, crucile returnează o singură valoare, adevărată sau falsă: anyreturnează adevărat dacă comparația este adevărată pentru cel puțin un element; allreturnează adevărat dacă comparația este adevărată pentru toate elementele. [68]
Folosind încrucișări, este posibil să măriți sistemul de tipări cu o anumită formă de programare generică care restricționează variabilele la încrucișări de tip.
subsetul Color of Any where RGB_Color | CMYK_Color ; sub get_tint ( Culoare $culoare , Num $opacitate ) { ... }Crossover-urile sunt obiecte speciale care împart execuția codului în fire potențial paralele . Și sunt concepute special pentru a fi utilizate într-un context boolean: nu puteți accesa conținutul lor direct fără a le converti într-un șir, care le distinge, de exemplu, de seturi și alte colecții. [68]
În limbajele de nivel scăzut, macrocomenzile au devenit sinonime cu înlocuirea textului în codul sursă datorită asocierii cu preprocesorul C. Cu toate acestea, în limbile de nivel înalt, cum ar fi Lisp , care a predat C , macrocomenzile erau mai puternice. [69] Raku a profitat de acest concept de macrocomenzi asemănător cu Lisp. [48] Puterea acestui tip de macro se bazează pe operarea programului ca o structură de date de nivel înalt, mai degrabă decât text și pe accesul la toate caracteristicile limbajului.
O definiție macro în Raku arată ca o definiție de subrutină sau metodă. Și o astfel de macrocomandă poate funcționa atât cu codul sursă, cât și cu un arbore de sintaxă abstractă și o combinație a acestor două lucruri.
macro salut ( $ce ) { quasi { spune "Bună ziua { {{{$ce}}} }" }; }În exemplul de mai sus, argumentul macro este analizat înainte de executarea macro-ului, ceea ce duce la mesaje de diagnosticare a compilatorului mai informative. Cu toate acestea, deoarece execuția corpului macro are loc în timpul compilării (pentru fiecare caz de utilizare), poate fi aplicată o mare varietate de tehnici de optimizare . Cu ajutorul macrocomenzilor, este chiar posibil să faceți cea mai mare parte a activității unor programe înainte de a începe executarea .
În Raku, identificatorii pot conține și apostrofe și cratime în plus față de litere, cifre și liniuțe de subliniere, atâta timp cât sunt urmate de litere. Literele includ caractere Unicode „corespondente” (care depind de implementare) , care sunt definite în Rakudo și MoarVM ca toate caracterele Unicode din categoria „L”. [70]
Folosirea cratimelor în loc de liniuțe de subliniere se numește „ cazul kebab ”. [71] [72] [73]
Meta-operatorii sunt operatori care pot fi parametrizați de alți operatori, la fel cum funcțiile pot lua ca parametri alte funcții . [74]
Meta operator de atribuirePerl a moștenit operatori în limbajul C precum +=și *=așa mai departe. Raku le generalizează la un meta operator. Pentru orice operator binar, opputem scrie:
$x op = $y ; # sau $x [op]= $yCe înseamnă:
$x = $x op $y ;Mai mult, acest lucru funcționează și pentru operatorii definiți de utilizator.
HiperoperatoriSunt similare cu operatorul mapdin Perl. Forțați operatorii să opereze pe toate valorile matricei. Poate fi aplicat atât operatorilor binari cât și unari. [75]
De exemplu, următorul cod va crea o matrice care conține toate elementele matricei @amărite cu unu:
@aPlusOne meu = @a "+" 1 ; # sau @a >>+>> 1Direcția parantezelor unghiulare afectează comportamentul atunci când rețele de lungimi diferite sunt transmise ca parametri. [75] Aceste „săgeți” arată de unde provine lungimea rezultatului operației.
Un exemplu de utilizare a unui operator hiper cu un operator unar:
my @a = 1 , 2 , - 3 ; @b meu = -<< @a ; # [-1 -2 3]Hiperoperatorii funcționează nu numai pentru matrice plate, ci și pentru matrice imbricate. [76]
Reducere meta operatorMeta operatorul de reducere poate fi utilizat cu orice operator infix , transformându-l într-un operator de reducere a listei . Este ca și cum operatorul s-ar aplica la primele două elemente, apoi la valoarea rezultată și la al treilea element și așa mai departe până rămâne o singură valoare. Suma, produsul, maximul, minimul etc. pot actiona ca un parametru-operator. Acesta este un mecanism extrem de puternic care, de exemplu, traduce operatorul +într-un operator de sumă de listă, ca în exemplul de mai jos.
spune "Suma numerelor întregi de la 0 la 99 este: " , [+] ^ 100 ; Operator încrucișatSe comportă atât ca operator, cât și ca meta-operator. [77]
Operatorul încrucișat [75] găsește produsul direct al listelor ordonate în așa fel încât enumerarea elementelor din operandul din dreapta să fie mai rapidă decât din operandul din stânga, [77] returnând o secvență de liste:
1 .. 3 X <ab c> X <de f> ; # ((1 ad) (1 ae) (1 af) # (1 bd) (1 be) (1 bf) # (1 cd) (1 ce) (1 cf) # (2 ad) (2 ae) ( 2 af) # (2 bd) (2 be) (2 bf) # (2 cd) (2 ce) (2 cf) # (3 ad) (3 ae) (3 af) # (3 bd) (3 be ) (3 bf) # (3 cd) (3 ce) (3 cf))Meta operatorul restrânge listele interne folosind operatorul parametru: [77]
1 .. 3 X ~ <ab c> X ~ <de f> ; # (1ad 1ae 1af 1bd 1be 1bf 1cd 1ce 1cf # 2ad 2ae 2af 2bd 2be 2bf 2cd 2ce 2cf # 3ad 3ae 3af 3bd 3be 3bf 3cd 3ce 3cf) Operator zipDin engleză. fermoar - fermoar . [78]
La fel ca operatorul încrucișat, combină elemente ale listelor, [75] dar returnează o secvență care conține mai întâi primele elemente ale fiecărei liste, apoi cele doua elemente ale fiecărei liste și așa mai departe. [79]
<ab c> Z <1 2 3 4> ; # ((a 1) (b 2) (c 3)) 100 , 200 Z + 42 , 23 ; # (142 223) Operatori inversiOperatorul meta R( ing. inversat ) vă permite să schimbați argumentele operatorului original.
spune „Unul împărțit la trei egali” , 3 R / 1 ; Imbricarea meta-operatorilorRezultatul aplicării unui meta-operator unui operator este un alt operator, căruia i se poate aplica din nou meta-operatorul și așa mai departe. Pentru a dezambigua sintaxa, sunt permise paranteze pătrate. [80]
my @a = 1 , 2 , 3 ; my @b = 5 , 6 , 7 ; @a >>>>> @b ; # Eroare de analiză. @a >>[>]>> @b ; # [False False False] # Aici, operatorului de comparație se aplică hiperoperatorul >> >>. # Meta-operatorul încrucișat aplică # operatorului de meta-atribuire # parametrizat de operatorul de adăugare: @a X [+=] @b ; # (6 12 19 7 13 20 8 14 21) # Din cauza operatorului cross-meta, atribuirea a fost făcută # pentru fiecare element al tabloului @a cu fiecare element al tabloului @b, # ceea ce este echivalent cu adăugarea fiecărui element al tabloului @a # a sumei elementelor matricei @b: spune [+] @b ; #18 spune @a ; # [19 20 21]Ca și alte limbaje moderne, Raku este proiectat pentru a sprijini programarea simultană și asincronă.
Raku oferă un API simplu, modular și de nivel înalt pentru scrierea codului concurent, independent de modul în care mașina virtuală implementează acest API. În plus, unele caracteristici ale limbii pot funcționa implicit asincron. Pentru a asigura manevrabilitate și compatibilitate între aceste funcții, codul utilizatorului ar trebui să evite, pe cât posibil, utilizarea interfețelor de nivel scăzut ( fire de execuție , programatori, blocări ). [81]
Promisiunile [82] [83] sunt mecanismul central de nivel înalt , care sunt rezultatele calculelor obținute înainte de finalizarea lor efectivă. Ele pot fi date, executate și încălcate. Astfel, au trei stări posibile. Puterea acestui mecanism constă în capacitatea de a le combina și de a le conecta în lanțuri:
my $p1 = Promisiune . nou (); my $p2 = $p1 . apoi ({ spune „Rezultatul celei de-a doua promisiuni.” });Aici thenasigura executarea $p2numai dupa executarea $p1.
Există și engleză. Rechizite („stocuri”) și ing. Furnizori („furnizori”) - un mecanism pentru crearea fluxurilor de date asincrone cu capacitatea de a procesa fiecare mesaj de către mai mulți destinatari simultan, similar modului în care lucrează handlerii de evenimente în alte limbaje de programare. [81] Acest mecanism poate fi utilizat pentru programarea bazată pe evenimente .
În cele din urmă, canalele ( canalele engleze ) sunt cozi FIFO sigure pentru fire , similare conductelor denumite din sistemele de operare, dar care funcționează în cadrul procesului curent. Diferența cheie față de este că o citire dintr-o țeavă este o coadă, [81] i.e. o valoare poate fi citită o singură dată. Supply
Programul „Bună lume!” adesea folosit pentru a demonstra sintaxa de bază a unei limbi. În Raku arată astfel:
spune „Bună, lume” ;Deși, desigur, există mai multe moduri de a o exprima. [84]
Calcul factorial , definit în mai multe moduri:
# Utilizarea recursiunii cu un construct „dacă-altfel”. subfapt ( UInt $n --> UInt ) { dacă $n == 0 { 1 } else { $n * fapt ( $n-1 ) } } # Utilizarea recursiunii cu „dacă” # ca modificator de expresie. subfapt ( UInt $n --> UInt ) { return 1 if $ n == 0 ; returnează $n * fapt ( $n-1 ); } # Utilizarea recursiunii cu constructul „când”. subfapt ( UInt $n --> UInt ) { când $n == 0 { 1 } implicit { $n * fapt ( $n-1 ) } } # Folosind operatorul ternar. subfapt ( UInt $n --> UInt ) { $n == 0 ?? 1 !! $n * fapt ( $n-1 ) } # Utilizarea expedierii multiple. fapt multiplu ( 0 ) { 1 } fapt multiplu ( UInt $n --> UInt ) { $n * fapt ( $n - 1 ) } # Utilizarea meta operatorului de reducere. subfapt ( UInt $n --> UInt ) { [*] 1 .. $n } # Definiția operatorului factorial, # implementat prin meta-operatorul de reducere. sub - postfix: <!>( UInt $n --> UInt ) { [*] 1 .. $n } # Utilizarea cuvântului cheie „state” pentru memorare. subfapt ( UInt $n --> UInt ) { stare %cunoscută = 0 => 1 ; returnează %cunoscut { $n } dacă %cunoscut { $n }: există ; %cunoscut { $n } = $n * fapt ( $n-1 ); returnează %cunoscut { $n }; }QuickSort este un algoritm de sortare binecunoscut. Implementarea sa folosind paradigma funcțională poate fi scrisă succint [a] astfel:
# O listă goală sortată este o listă goală. sortare rapidă multiplă ([]) { () } # Altfel, luați primul element ca pivot... sortare rapidă multiplă ([ $pivot , * @rest ]) { # Împărțiți elementele într-o listă cu cele # mai mici decât pivotul și cele # mai mari decât pivotul. my @before = @rest . grep (* înainte de $pivot ); meu @ după = @rest . grep (* după $pivot ); # Sortați aceste subliste și concatenați rezultatul. plat ( sortare rapidă ( @înainte ), $pivot , sortare rapidă ( @după )) }Acest puzzle este adesea folosit pentru a introduce recursiunea în informatică . Această implementare folosește multimetode cu un literal 0 ca parte a .
multi sub hanoi ( 0 , $, $, $) { } # Fără discuri. Nu este nimic de transferat. multi sub hanoi ( $n , $a = 'A' , $b = 'B' , $c = 'C' ) { # $n discuri si trei tije: A, B, C. hanoi $n - 1 , $ a , $c , $b ; # Mutați ($n - 1) unități de la A la B spuneți „Mutați unitatea $n de la $a la $c”. ; # Muta ultimul disc de la A la C. hanoi $n - 1 , $b , $a , $c ; # Mută ($n - 1) discuri de la B la C. } hanoi ( 5 ); # Soluție pentru cinci discuri.Perl | |
---|---|
oameni |
|
Lucruri | |
Cadre |
|
|