Dernière version sur https://formation-perl.fr/guide-perl.html
© 2002-2024 Sylvain Lhullier - Permission est accordée de copier et distribuer ce document sans modification
et à condition de fournir un lien vers la page https://formation-perl.fr/guide-perl.html
Envie d'une formation Perl ?
Sylvain Lhullier propose des formations au langage Perl,
contactez-le.
Une fonction est un ensemble d'instructions regroupées de manière à être utilisées plusieurs fois sans avoir à dupliquer du code.
Le mot clef sub
permet de définir des fonctions en Perl.
Les arguments d'une fonction sont des valeurs scalaires, à l'exclusion
de toutes autres (on verra comment faire en sorte de passer un tableau
en argument) ; ces paramètres sont accessibles via la variable
spéciale @_
(qui est donc un tableau). Modifier
une valeur de @_
modifiera les variables d'appel,
il est donc d'usage d'en faire une copie avant manipulation.
sub maJolieFonction { my ($x,$y,$t) = @_; ... instructions ... return $z; }
Ces quelques lignes définissent une nouvelle fonction dont le nom est
maJolieFonction
. Cette fonction copie dans trois
variables locales les trois premières valeurs du tableau
@_
, c'est-à-dire ses trois premiers paramètres
(les règles classiques d'affectation entre listes et tableaux s'appliquent ici).
Je vous conseille de toujours commencer vos fonctions par une ligne
copiant les valeurs de @_
et de ne plus utiliser
@_
dans la suite de la fonction (sauf cas spécial).
Si votre fonction attend un seul paramètre, la syntaxe peut être la suivante :
my ($x) = @_;
mais ne peut pas être :
my $x = @_; #incorrect
Cette ligne est incorrecte, car dans ce cas, la variable
$x
aurait pour valeur le nombre de paramètres
(affectation d'un tableau à un scalaire).
La syntaxe suivante peut aussi être utile :
my ($x,@t) = @_;
la variable $x
reçoit le premier paramètre et
le tableau @t
reçoit tous les paramètres restants.
Enfin, une autre écriture que vous verrez souvent dans les programmes Perl est la suivante :
my $x = shift;
celle-ci s'appuie sur le fait que dans une sous-routine, la fonction
shift
travaille par défaut sur
@_
.
L'instruction return
met fin à l'exécution de la
fonction et on peut lui fournir une expression qui sera alors la
valeur de retour de la fonction.
La fonction ainsi définie peut être appelée au moyen de la syntaxe suivante :
maJolieFonction(10,20,30);
Dans ce cas, l'éventuelle valeur de retour est ignorée. Pour récupérer cette valeur :
$v = maJolieFonction(10,20,30);
Il est possible d'omettre les parenthèses lors de l'appel à une fonction :
maJolieFonction 10,20,30; # À éviter
mais cela peut créer des ambiguïtés et je vous déconseille donc cette syntaxe.
S'il est possible en Perl d'imposer le nombre d'arguments pour une fonction
(nous n'en parlerons pas ici), cela n'est pas fait par défaut.
Rien ne nous empêche en effet d'appeler la fonction maJolieFonction
précédemment définie avec deux ou quatre arguments, alors qu'elle
semble en attendre trois ; si on l'appelle avec deux arguments, la variable
$t
vaudra undef
; par contre
si on l'appelle avec plus de trois arguments, les valeurs suivantes
seront ignorées. Mais cette particularité du langage est parfois bien
pratique, notamment pour écrire des fonctions à nombre variable d'arguments.
Les variables déclarées au moyen de my
dans une fonction ne seront visibles qu'à l'intérieur même de la fonction,
dans le code qui suit la déclaration.
Dans une fonction, il est possible d'accéder aux variables définies
à la « racine » du programme (c'est-à-dire en dehors de toute fonction) : il s'agit
donc de variables globales. Si une variable locale a le même nom
qu'une variable globale, cette dernière est masquée par la variable locale :
my $a = 3; my $b = 8; my $c = 12; sub maJolieFonction { my $a = 5; print "$a\n"; # affiche 5 print "$b\n"; # affiche 8 $c = 15; # modification de la variable globale print "$c\n"; # affiche 15 } maJolieFonction(); print "$a\n"; # affiche 3 print "$b\n"; # affiche 8 print "$c\n"; # affiche 15
De manière plus générale, les variables déclarées au moyen de my
sont visibles jusqu'à la fin du plus petit bloc qui les englobe. En particulier, dans
une fonction...
sub maJolieFonction2 { my $d = -3; if( ... ) { my $d = 4; my $e = 8; print "$d\n"; # affiche 4 print "$e\n"; # affiche 8 } print "$d\n"; # affiche -3 print "$e\n"; # $e n'existe pas ici }
Il est tout à fait possible de faire renvoyer plusieurs scalaires par une fonction, il suffit d'utiliser une liste. Voici des exemples de syntaxe de liste renvoyée par des fonctions :
return ($x,$z); return @t;
Dans le second cas, le tableau est converti en liste. Et voici comment il est possible de récupérer ces valeurs :
@s = fonction(...); ($j,$k) = fonction(...);
Ces deux manières de procéder peuvent parfaitement être utilisées
chacune dans les deux cas de return
pré-cités
(ce sont toujours les mêmes règles d'affectation qui s'appliquent).
Voici un exemple complet de programme en Perl avec une fonction :
1: #!/usr/bin/perl 2: use strict; 3: use warnings; 4: my $t = "Bonjour Larry"; # variable globale 5: print "$t\n"; # avec ou sans parenthèses 6: sub f { 7: my ($x,$z) = @_; # deux arguments attendus 8: my $m = $x*$z; 9: printf("%d\n", $m); 10: return ($x+$z,$m); # retourne une liste 11: } 12: my @t = f(3,5); 13: print "$t $t[0] $t[1]\n";
Un bon programme Perl commence toujours par les première et deuxième lignes.
Si la variable scalaire $t
, elle, est globale,
en revanche les variables $x
, $z
et
$m
sont locales à la fonction.
En ligne 12, le tableau @t
reçoit pour valeur la liste renvoyée
par la fonction. Notez bien qu'il n'y a aucun conflit entre les variables
$t
et @t
; en effet, l'instruction de la
dernière ligne procède d'abord à l'affichage de la variable scalaire
$t
puis du premier et deuxième éléments du
tableau @t
(les crochets permettent de savoir
qu'il s'agit d'éléments d'un tableau).
Voici un exemple de fonction. Elle est récursive (c'est-à-dire qu'elle fait appel à elle-même) : nous allons calculer la factorielle d'un nombre. Par définition, F(0)=F(1)=1 et F(n)=n×F(n-1) pour tout n supérieur à 1 :
sub Fact { my ($n) = @_; return 1 if( $n == 1 || $n == 0 ); return $n * Fact($n-1); } print Fact(5)."\n"; # affiche 120
Aussi lisible que dans tout autre langage.
Nous allons ici illustrer l'usage des listes et des tableaux par un exemple mathématique : le crible d'Ératosthène. Cet algorithme permet de calculer tous les nombres premiers inférieurs à un nombre donné n.
Son principe est le suivant : nous construisons tout d'abord la liste de tous les entiers de 2 à n. Ensuite, à chaque itération, nous supprimons de la liste tous les multiples du premier nombre de la liste et signalons ce premier nombre comme étant premier. Au premier tour de boucle, je supprime tous les nombres pairs et dis que 2 est premier. Au suivant, je supprime tous les multiples de 3 et affirme que 3 est premier. Au tour suivant, c'est le 5 qui est au début de la liste (4 étant multiple de 2, il a déjà été supprimé), j'enlève de la liste les multiples de 5 et annonce la primalité de 5, etc. L'algorithme se termine lorsque la liste est vide, j'ai alors déterminé tous les nombres premiers inférieurs à n.
Voici la fonction réalisant cet algorithme en Perl :
sub Crible { my ($n) = @_; # Liste initiale : my @nombres = (2..$n); # Liste des nombres premiers trouvés : my @premiers = (); # Tant qu'il y a des éléments (un tableau # en contexte booléen vaut faux s'il est vide) : while( @nombres ) { # On extrait le premier nombre my $prem = shift @nombres; # On indique qu'il est premier push @premiers, $prem; # On supprime ses multiples @nombres = grep { ( $_ % $prem )!=0 } @nombres; } # On renvoie la liste des nombres premiers return @premiers; }
Quiconque a déjà réalisé cet algorithme en C ou C++ comprendra la joie que cette concision procure...