Formation Perl - Formateur Perl

Formation de qualité par un spécialiste Perl

Sylvain Lhullier

Version 1.4.5
mars 2023


Guide Perl - Débuter et progresser en Perl

Dernière version sur  https://formation-perl.fr/guide-perl.html
© 2002-2023 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.

5. Écrire une fonction

Une fonction est un ensemble d'instructions regroupées de manière à être utilisées plusieurs fois sans avoir à dupliquer du code.

5.1. Déclaration

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.

5.2. Appel

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.

5.3. Visibilité des variables

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
}

5.4. Une liste pour valeur de retour

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).

5.5. Premier exemple de fonction

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).

5.6. Autre exemple : une fonction récursive

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.

5.7. Dernier exemple : le crible d'Ératosthène

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...


Contact © 1999-2024 formation-perl.fr
Formation Perl - Formation Perl intra entreprise - Formation Perl inter entreprise - Formateur Perl - Formateur Perl délégation
Formation Perl Formateur Perl Appartement à louer à Noisy-le-Grand Bric-à-Brac