Le langage Perl 6, poursuite du tour d'horizon

GNU/Linux Magazine n° 194 | juin 2016 | Laurent Rosenfeld
Creative Commons
  • Actuellement 0 sur 5 étoiles
0
Merci d'avoir participé !
Vous avez déjà noté cette page, vous ne pouvez la noter qu'une fois !
Votre note a été changée, merci de votre participation !
Nous poursuivons ici le tour d'horizon du nouveau langage Perl 6 en abordant les structures de contrôle, les fonctions et la construction de nouveaux opérateurs.

 

Note

Dans le premier volet de ce tour d'horizon du nouveau langage de programmation Perl 6, nous avons notamment présenté les différents types de variables et les principaux opérateurs du langage.

Le présent article décrit notamment les principales structures de contrôle : les conditions (ifunlessgiven ... when) et les boucles (forwhileuntilloop). Il montre ensuite comment créer des fonctions dotées de signatures fortement ou faiblement typées, au choix de l'utilisateur ; on verra notamment comment des signatures différentes permettent d'écrire des fonctions (fonctions dites multiples) ayant le même nom, mais faisant des choses différentes selon le nombre et le type de leurs arguments.

Nous verrons enfin combien il est facile de créer dynamiquement de nouveaux opérateurs permettant d'étendre le langage.

Pour commencer ce deuxième article consacré au langage Perl 6, nous voudrions vérifier, cher lecteur, que vous avez bien assimilé le premier article et vous avons réservé à cette fin une petite surprise : nous allons faire un petit examen de contrôle.

- Exercice 1 : la fonction interne lcm renvoie le plus petit multiple commun (PPMC) entre deux nombres. Écrire un programme qui affiche le plus petit nombre positif divisible par tous les nombres de 1 à 20.

- Exercice 2 : écrire un programme qui calcule la somme des chiffres du nombre factoriel de 100 ;

- Exercice 3 : trouver la différence entre le carré de la somme des 100 premiers entiers naturels et la somme des carrés des 100 premiers entiers.

Nous n'avons pas encore étudié les conditions (if, etc.), ni les boucles (for, while, etc.), ni les fonctions. Il faut donc trouver dans ce que nous avons déjà appris d'autres solutions pour résoudre ces problèmes. Un indice : relisez tout le chapitre sur les opérateurs. Nous ne relèverons pas les copies, mais essayez vraiment de faire ces exercices.

Lorsqu’au début de mes études d'informatique, j'ai dû faire ce genre d'exercices dans le langage de programmation choisi à l'époque par mes enseignants (Pascal ou C, par exemple), je m'attendais à devoir écrire quelques dizaines de lignes de code pour chacun d'entre eux. Ici, en Perl 6 et avec un modèle de programmation issu de la programmation fonctionnelle, chacun peut se faire en une seule petite ligne de code. Voilà notamment ce que nous voulons dire quand nous disons que Perl 6 est un langage puissant et expressif.

Vous trouverez des solutions à ces exercices dans l'encadré plus loin.

Note

Solution des exercices

Voici des solutions possibles aux exercices proposés dans la première page de cet article.

PPMC des nombres de 1 à 20

Le métaopérateur de réduction [...] permet d'appliquer un opérateur successivement à tous les éléments d'une liste. Il suffit de l'utiliser avec l'opérateur lcm sur la liste des nombres de 1 à 20 :

> say [lcm] 1..20;

232792560

Somme des chiffres de factorielle 100

Nous utilisons ici deux fois le métaopérateur de réduction [...] : une première fois avec la multiplication pour calculer 100! et une seconde fois pour faire la somme des chiffres du résultat. Ce qui donne :

> say [+] split '', [*] 2..100;

648

Carré de la somme moins somme des carrés

Perl 6 calcule facilement la somme des 100 premiers nombres avec [+] 1..100. L'hyperopérateur  <<...>> permet de calculer les carrés des cent premiers entiers et le métaopérateur [...] de réduire cette liste de carrés à leur somme. Ce qui permet d'écrire :

say ([+] 1..100)**2 - [+] (1..100) <<**>> 2;

25164150

On pourrait alléger le calcul en remarquant que la somme des 100 premiers entiers naturels est égale à (100 x 101) / 2 = 5050, mais le but était ici surtout d'employer les hyperopérateurs et métaopérateurs du langage.

1. Structures de contrôle : conditions et boucles

1.1 Les conditions simples

La condition if / else est classique. Sa seule particularité est que, contrairement à beaucoup de langages, elle ne nécessite pas de parenthèses autour de la condition :

my $âge = 19;

if $âge >= 18 {

    say "Vous êtes un adulte."

} else {

    say "Vous êtes un jeune."

}

À noter que le point-virgule n'est pas nécessaire avant une accolade fermant un bloc. On peut également tester successivement plusieurs conditions avec des clauses elsif :

if $âge < 12 {

    say "Enfant"

} elsif $âge < 18 {

    say "Adolescent"

} else {

    say "Adulte"

}

Une condition if peut également se placer après l'instruction (on parle alors d'instruction modifiée) :

> say "Bienvenue sur ce site" if $âge >= 18;

Bienvenue sur ce site

Cette syntaxe est concise et pratique, mais n'autorise pas de clause else ou elsif.

La condition unless inverse la condition :

say  "Désolé : réservé aux adultes !" unless $âge >= 18;

# équivalent à :

say  "Désolé : réservé aux adultes !" if not $âge >= 18;

La construction given ... when correspond au switch d'autres langages, mais permet une formulation beaucoup plus riche et variée des conditions :

my Int $âge = 18;

given $âge {

    when *..^0 { say "âge négatif ? Hum..." };

    when 0..2  { say "Bébé" };

    when 3..12 { say "Enfant" };

    when *..17 { say "Adolescent" };

    when   18  { say "tout jeune adulte" };

    default    { say "Adulte"}

}

Dès que l'une des conditions est satisfaite, les conditions suivantes ne sont pas évaluées. La condition *..17, c'est-à-dire compris entre   et 17, est donc ici correcte et en fait équivalente à 13..17 puisque l'on n'arrive à cette condition que si les trois conditions précédentes ont échoué (ce qui ne veut pas dire qu'il soit recommandé d'écrire une telle bizarrerie contre-intuitive, donnée ici à seul titre d'exemple).

On peut inviter le programme à continuer l'évaluation des conditions suivantes même si une condition est satisfaite avec une instruction proceed :

my $var = 42;

given $var {

    when 0..50 { say 'Compris entre 0 et 50'; proceed };

    when Int   { say "Un entier"; proceed};

    when /4/   { say "Contient le chiffre 4"; proceed };

    when not .is-prime { say "Non premier";   proceed };

    when 42    { say "réponse à la Grande Question" }

}

Ici, grâce aux instructions proceed, chacun des cinq messages est affiché l'un après l'autre puisque toutes les conditions sont successivement satisfaites.

1.2 L'opérateur ternaire

L'opérateur ternaire, issu du langage C, utilise ?? et !!:

> my ($x, $y) = (1, 2);

(1 2)

> say "Max = ", $x > $y ?? $x !! $y;

Max = 2

On peut enchaîner plusieurs de ces opérateurs :

my Int $âge = 18;

say $âge <= 2 ?? "Bébé"

   !! $âge <= 12 ?? "Enfant"

   !! $âge < 18 ?? "Ado"

   !! $âge == 18 ?? "Jeune adulte"

   !! "Adulte";

Ce qui imprime « Jeune adulte ».

1.3 Les boucles

En Perl 6, la boucle la plus commune est la boucle for, qui itère sur une liste de valeurs ou les éléments d'un tableau et dont la syntaxe la plus commune est la suivante :

> my @tableau = [0..10];

[0 1 2 3 4 5 6 7 8 9 10]

> for @tableau -> $val { print $val * 2, " "};

0 2 4 6 8 10 12 14 16 18 20 >

Cette construction s'appelle un « bloc pointu ». Ici, la variable $val est un alias en lecture seule sur les valeurs successives du tableau ; elle n'a pas besoin d'être pré-déclarée et sa portée est naturellement limitée au bloc d'instructions de la boucle for. Le lecteur féru de programmation fonctionnelle aura peut-être reconnu dans cette construction de « bloc pointu » à la fois une lambda et une fermeture anonyme.

La boucle for ci-dessus itère directement sur les éléments du tableau, ce qui correspond au besoin le plus fréquent. Si l'on a besoin d'itérer sur les indices, il suffit de créer à la volée une liste des indices à l'aide de l'opérateur intervalle .. et de la fonction ou méthode end (retournant l'indice du dernier élément d'un tableau) et d'itérer sur cette liste :

my @mois = <none jan fév mar avr mai jun>;

for 1..end @mois -> $num { say "$num \t @mois[$num]" };

# ou: for 1..@mois.end  -> ...

On peut également utiliser les itérateurs de listes du langage, par exemple keys pour récupérer la liste d'indices :

my @nombres = <zéro un deux trois quatre cinq>;

for @nombres.keys -> $indice  { say "$indice \t @nombres[$indice]" };

Ou encore kv pour récupérer à la fois les indices et les éléments correspondants :

for @nombres.kv -> $indice, $nombre  { say "$indice \t $nombre" };

Si l'on a besoin de modifier les valeurs du tableau, il faut un alias en lecture et écriture, ce qui se fait à l'aide d'un bloc « doublement pointu » :

my @tableau = [0..10];

for @tableau <-> $val { $val *= 3 }

say @tableau;  # affiche [0 3 6 ... 30]

Une syntaxe d'expression modifiée est également possible :

> print $_ * 2, " " for [0..10];

0 2 4 6 8 10 12 14 16 18 20 >

Une boucle for est un itérateur et peut donc travailler de façon « paresseuse » (c'est-à-dire qu'elle ne traite les éléments qu'au fur et à mesure des besoins), même sur une liste « infinie ». Employer une boucle for est donc une façon idiomatique d'itérer sur les lignes d'un fichier :

for "fichier.txt".IO.lines -> $ligne {

    say $ligne unless $ligne ~~ /^'#'/

}

La boucle while ressemble à celle des autres langages communs et exécute la boucle tant que la condition est vraie, si ce n'est que les parenthèses ne sont pas nécessaires autour de la condition :

> my $var = 0;

0

> while $var < 5 { print 3 * ++$var, " ";}

3 6 9 12 15 >

Une boucle until exécute le bloc de la boucle tant que la condition est fausse. Voici un exemple utilisant une syntaxe d'instruction modifiée :

my $x = 0;

print $x++ until $x > 5; # imprime 012345

Vous pouvez enfin utiliser une boucle loop, qui correspond à la boucle for du langage C et des langages apparentés :

loop (my $i=0; $i < 5; $i++) {

  say "Le nombre actuel est : $i"

}

Cette syntaxe permet de construire des boucles complexes, mais il est rare d'avoir besoin de ce genre de boucle en Perl 6 : la boucle for de Perl 6 est généralement bien plus pratique. C'est la seule construction de boucle pour laquelle les parenthèses restent nécessaires autour des conditions/initialisations. Sa seule utilisation fréquente est la façon idiomatique d'écrire une boucle infinie :

loop {...}

Les instructions next et last permettent, respectivement, de recommencer à l'itération suivante et de sortir immédiatement d'une boucle for, while ou autre :

for 1..20 -> $i {

    next if 3 < $i <= 7;

    last if $i == 10;

    print "$i ";

}   # imprime 1 2 3 8 9

2. Fonctions ou sous-routines

Les fonctions permettent de regrouper un ensemble de fonctionnalités. On déclare une fonction à l'aide du mot-clef sub (pour subroutine) suivi de son identifiant (son nom), et l'on définit ce qu'elle fait dans un bloc de code placé entre accolades.

saluer();   # imprime "Bonjour ..."

sub saluer {

     say 'Bonjour tout le monde.';

}

Contrairement à certains langages, la fonction peut être appelée avant sa définition. L'instruction saluer(); est l'appel de la fonction. C'est lors de l'exécution de cette ligne de code que la fonction s'exécute.

2.1 Arguments et signatures

La fonction ci-dessus ne prend pas de paramètres en entrée et ne renvoie pas de valeurs de retour, ce qui limite quelque peu son utilité. La plupart des fonctions utiles ont besoin de données en entrée, qui leur sont fournies sous la forme d'arguments. Voici une fonction analogue avec le passage d'un argument :

saluer("Maître");   # imprime "Bonjour Maître."

sub saluer ($titre) {

     say "Bonjour $titre.";

}

Ici, l'appel de la fonction se fait avec un argument, la chaîne "Maître". La définition de la fonction contient maintenant une signature placée entre parenthèses ; cette signature définit la variable $titre comme le paramètre (formel) que reçoit la fonction. Dans cet exemple, le paramètre $titre prend la valeur de l'argument d'appel, « Maître », et est utilisé ensuite dans le corps de la fonction. Cette signature est réduite à sa plus simple expression, mais elle a déjà pour effet d'obliger le code utilisateur à passer un argument (et un seul) lors de l'appel à la fonction. Si le nombre d'arguments est différent de un, cela génère une erreur.

Par défaut, les paramètres des fonctions sont des copies en lecture seule des arguments reçus (c'est une forme de passage de paramètre par valeur) et ne peuvent donc pas être modifiés dans la fonction. Mais on peut changer ce comportement grâce à des traits (propriétés définies à la compilation) tels que is rw (lecture écriture, comme lors d'un passage de paramètres par référence) ou is copy (copie locale à la fonction et modifiable) :

my Int $valeur = 5;

ajoute-deux($valeur);

say $valeur; # -> 7

sub ajoute-deux (Int $x is rw) { $x += 2}

La signature permet non seulement de vérifier le nombre d'arguments, mais aussi leur type. Voici un exemple de fonction ayant une signature un peu plus complexe :

sub multiplie (Int $x, Int $y) {

    say "Produit = ", $x * $y

}

multiplie(3, 4); # -> Produit = 12

Ici, la signature comporte deux paramètres, $x et $y. Ce sont des paramètres positionnels : le paramètre $x reçoit la valeur du premier argument passé à la fonction et le paramètre $y reçoit le second argument. En outre, ces deux paramètres sont de type entier. Le compilateur vérifiera donc que la fonction est bien appelée avec deux arguments de type entier, sinon il émettra une erreur. À noter que si la fonction est comme ici déclarée avant son appel, il est possible d'appeler la fonction en omettant les parenthèses autour des arguments :

multiplie 3, 4;  # -> Produit = 12

Cette fonction ne peut multiplier que des entiers, ce qui en limite l'utilité. Il est bien sûr possible de définir des signatures sur des types numériques quelconques, par exemple en utilisant le type générique Numeric.

Il peut être difficile de se souvenir de l'ordre des paramètres positionnels, surtout quand la fonction accepte de nombreux arguments. Il est dans ce cas possible d'utiliser des paramètres nommés rendant l'ordre des arguments indifférents, avec la syntaxe suivante :

sub divise (Numeric :$dividende, Numeric :$diviseur) {

    say $dividende/$diviseur

}

divise(dividende => 12, diviseur => 4);  # -> 3

divise diviseur => 4, dividende => 12 ;  # idem

Le second exemple d'appel de la fonction divise ci-dessus montre que les parenthèses sont ici encore optionnelles si la fonction a été déclarée avec sa signature avant son appel.

2.2 Fonctions multiples

Il est possible de définir avec le mot-clef multi des fonctions spéciales ayant le même nom, mais se distinguant par leur signature (nombre et type des arguments). Perl détermine quel exemplaire de la fonction appeler en fonction de la signature (processus analogue à la résolution des méthodes en programmation orientée objet).

multi salue ($nom)         {say "Bonjour $nom"}

multi salue ($nom, $titre) {say "Bonjour $titre $nom"}

salue("George Lucas");    # -> Bonjour George Lucas

salue "Yoda", "Maître";   # -> Bonjour Maître Yoda

Ici, c'est le nombre d'arguments de la fonction qui permet à Perl 6 de déterminer quelle version de salue appeler. La distinction pourrait aussi se faire sur le type (voire le « sous-type »).

Beaucoup des opérateurs et des fonctions ou méthodes internes de Perl 6 sont définis comme des fonctions multiples. Cela signifie qu'en utilisant une signature n'existant pas en interne, il est possible de redéfinir ou surcharger ces fonctions ou opérateurs.

2.3 Valeurs de retour

Toutes nos fonctions jusqu'ici se contentaient d'afficher quelque chose à l'écran. Très souvent, il est souhaitable qu'une fonction se contente de prendre des paramètres en entrée et de renvoyer des valeurs de retour, sans avoir d'effet de bord. Cela facilite la conception et la mise au point de programmes.

Voici la définition et l'utilisation d'une fonction renvoyant une valeur utile :

> sub carré ($x) { return $x * $x }

sub carré ($x) { #`(Sub|183561872) ... }

> say carré 3

9

Le mot-clef return indique explicitement que la fonction doit se terminer et renvoyer la valeur donnée. Et l'appel carré 3 renvoie à say la valeur 9. En fait, ce mot-clef n'était pas indispensable ici, car une fonction renvoie implicitement la dernière expression évaluée, si bien que la fonction aurait aussi bien pu s'écrire :

sub carré ($x) { $x ** 2 }

Cela suffit pour des fonctions simples n'ayant qu'un seul point de sortie, mais l'utilisation de return permet de définir finement le comportement d'une fonction et les valeurs de retour selon les conditions rencontrées.

3. Définir ou redéfinir un opérateur

Les opérateurs de Perl 6 sont en fait des fonctions ou des méthodes ayant souvent un nom un peu inhabituel et définissant quelques propriétés permettant de les utiliser : un opérateur est généralement doté d'une  précédence (priorité d'exécution), d'un type de notation syntaxique (préfixée, postfixée, infixée, etc.) et d'une associativité (comment il se comporte quand il y a plusieurs opérateurs de même précédence). Pour créer un nouvel opérateur, il faut au minimum définir son type de notation, et, selon le besoin, éventuellement préciser sa précédence et son associativité.

Nous pourrions par exemple utiliser le symbole euro «  » pour définir un opérateur de doublement d'un entier :

sub postfix:<€> (Int $n) {2*$n}

say 21€; # -> 42

Ce nouvel opérateur n'est sans doute pas très utile (et son nom n'est pas idéalement choisi pour ce qu'il fait), mais illustre simplement comment il est possible d'enrichir dynamiquement le langage.

À titre d'exemple d'un nom d'opérateur peut-être mieux choisi, utilisons le petit « 2 » en indice du clavier pour définir un opérateur d'élévation au carré :

sub postfix:<²>(Numeric $n) {$n**2}

say 5²;        # -> 25

say (3 + 4)²;  # -> 49

Perl 6 supportant les caractères unicodes, il est possible d'utiliser les symboles mathématiques (par exemple le symbole racine carrée), les lettres grecques, tibétaines ou d'autres langues, les guillemets japonais 「」, les pictogrammes normalisés, les lettres braille, etc. pour définir des opérateurs.

Un opérateur n'est pas nécessairement un caractère spécial unique, nous pourrions (ou du moins aurions pu, il y a quelques années, ce n'est plus très utile aujourd'hui) définir des opérateurs de conversion de francs en euros et réciproquement :

sub prefix:<f€> (Numeric $n) {$n/6.55957}

sub prefix:<€f> (Numeric $n) {$n*6.55957}

say f€ 6.56;   # -> 1.0000656

say €f 10;     # -> 65.5957

Définir un opérateur infixé ne pose pas plus de problème. Par exemple, voici un opérateur de calcul de la moyenne entre deux nombres :

sub infix:<moy> (Numeric $n, Numeric $m) {($n+$m)/2}

say 10 moy 5; # -> 7.5

L'opérateur ! de négation booléenne est de type préfixé, c'est-à-dire qu'il se place avant le terme auquel il s'applique. Nous pouvons réutiliser le même opérateur ! pour définir la factorielle, qui utilisera naturellement, comme en mathématiques, une notation postfixée :

sub postfix:<!> (Int $n) {

    [*] 2..$n

}

say 20!;      # -> 2432902008176640000

say ! False;  # -> True

Voici enfin un exemple dans lequel nous définissons aussi la précédence de l'opérateur. Il existe en Perl 6 un type Pair qui définit une paire clef-valeur et se note généralement clef => valeur. Nous pourrions vouloir utiliser ce type pour modéliser des couples de valeurs que nous désirons pouvoir additionner membre à membre. Il suffit de définir l'addition de paires et, tant qu'à faire, lui donner la même propriété de précédence que l'addition arithmétique :

multi sub infix:<+> (Pair $x, Pair $y) is equiv(&infix:<+>) {

    return $x.key + $y.key => $x.value + $y.value

}

my $a = 4=>3;

my $b = 7=>2;

say $a + $b; # -> 11 => 5

Le « trait » is equiv(&infix:<+>) précise que cet opérateur a la même précédence que l'opérateur d'addition. Si nous définissons une multiplication membre à membre sur le même modèle en lui donnant la même précédence que la multiplication, nous retrouverons les règles de précédence habituelles entre nos opérations sur les paires.

La création de nouveaux opérateurs est un moyen simple d'enrichir dynamiquement le langage. Pour des enrichissements plus complexes, il est possible de modifier dynamiquement la grammaire même de Perl 6, mais cela nécessiterait de présenter les grammaires de Perl et sortirait du cadre de cette brève présentation.

Conclusion

Nous avons fait un bref tour d'horizon de la syntaxe de base de Perl 6 et avons aussi essayé de présenter quelques-unes des caractéristiques (fonctions multiples, création de nouveaux opérateurs, etc.) qui le rendent particulièrement puissant et expressif.

Parmi celles que nous n'avons pas pu décrire faute de place (mais pourrons peut-être aborder dans des articles ultérieurs), Perl 6 offre en particulier :

- un nouveau système de programmation orientée objet particulièrement flexible, puissant et expressif, doté de classes, de méthodes et de rôles, la possibilité de créer facilement de nouveaux types, une introspection approfondie et une couche méta-objet permettant de modifier dynamiquement le comportement des objets et des classes ;

- un système d'expressions régulières nettoyé et refondu, rendu plus lisible et modulaire grâce aux regex nommées qui sont en quelque sorte des briques permettant de construire des expressions régulières bien plus puissantes tout en étant plus lisibles, et débouchant sur la création de véritables grammaires permettant l'analyse lexicale et syntaxique non seulement de texte HTML, JSON, XML, etc., mais aussi de langages de programmation : la grammaire utilisée par Perl 6 pour analyser les programmes Perl 6 est elle-même écrite en Perl 6, et il est même possible dans un programme ou un module d'ajouter de nouveaux éléments syntaxiques à la grammaire Perl 6 existante, ce qui rend le langage intrinsèquement malléable et évolutif ;

- un modèle de programmation fonctionnelle très enrichi, avec en natif le support aux listes paresseuses, la programmation en pipe-line, les fonctions d'ordre supérieur, les itérateurs, les hyperopérateurs, les fermetures, les lambdas, la curryfication, etc. ;

- un support exceptionnellement efficace de l'Unicode, probablement sans égal actuellement ;

-  un modèle de programmation parallèle, concurrente et asynchrone de haut niveau, bien plus puissant et expressif que les threads, sémaphores et verrous, fiable, robuste, facile à utiliser et extrêmement prometteur, s'ajoutant à la possibilité d'utilisation implicite par le compilateur de threads utilisant différents cores pour traiter des données en parallèle, ainsi qu'un support natif de la programmation évènementielle ;

- un support natif des structures de données multidimensionnelles de plus bas niveau (matrices, etc.) permettant d'envisager du calcul scientifique intensif ;

- un interfaçage particulièrement simple avec des bibliothèques C/C++, Java ou autres, ainsi qu'avec les anciennes versions de Perl, ce qui permet l'utilisation de modules Perl 5 en Perl 6 (ou l'inverse) et ouvre donc la voie à l'utilisation des modules Perl 5 du CPAN, l'une des plus vastes collections de bibliothèques logicielles libres au monde.

La liste ci-dessus pourrait se poursuivre sur plusieurs pages, mais nous nous arrêterons là pour éviter de lasser le lecteur. Tout cela fait de Perl 6 un langage exceptionnellement expressif et intrinsèquement malléable ; même ce qui n'existe pas dans le langage, vous pouvez presque toujours le créer dynamiquement à la demande.

Tout n'est pas encore parfait pour autant. Les performances d'exécution se sont considérablement améliorées depuis un an, mais elles laissent encore un peu à désirer dans certains cas. Les macros avancées ne sont pas encore implémentées et deux ou trois autres fonctionnalités initialement prévues (comme les entrées/sorties non bloquantes) sont encore incomplètement mises en œuvre. Quelques progrès sont donc encore nécessaires (et font l'objet de travaux intensifs), mais Perl 6 offre d'ores et déjà une palette de fonctionnalités que nous pensons très largement inégalée, même parmi les langages récents bénéficiant des ressources incomparablement plus abondantes d'entreprises richissimes comme Google, Apple, Microsoft, Oracle et quelques autres géants du Nasdaq.

Pour aller plus loin

Le site de téléchargement de Rakudo Star/Perl 6 : http://rakudo.org/downloads/star/

La documentation officielle (en anglais) sur Perl 6 est disponible à l'adresse suivante : doc.perl6.org

Plusieurs articles et tutoriels en français sont en ligne à l'adresse suivante : http://perl.developpez.com/cours/#TutorielsPerl6

Le site des Mongueurs de Perl fournit de nombreux liens complémentaires : http://mongueurs.pm/ressources/ref_perl6.html

Tags : Perl