Définition d'une sous-fonction
Nous avons vu qu'il peut être intéressant de créer des fichiers de fonctions, pour regrouper des commandes que l'on souhaite exécuter plusieurs fois, dans un même script principal, ou dans différents scripts.
Structurer un programme complexe, en un script principal qui appelle des fonctions spécifiques que l'on a définies pour réaliser des tâches bien déterminées, permet une évolution et une maintenance plus aisées de ce programme.
Un fichier de fonction .m peut contenir des sous-fonctions. Celles-ci ont la même structure qu'une fonction telle que définie précédemment, mais ne sont pas accessibles en dehors de la fonction principale. Les sous-fonctions favorisent la mutualisation de lignes de commandes, sans multiplier inutilement les fichiers.
Fonction locale
Soit une fonction définie dans un fichier .m.
Une fonction locale est une fonction définie dans le même fichier que la fonction principale (portant le nom du fichier) mais qui n'est utilisable que localement dans la fonction principale, ou par d'autres fonctions locales de ce même fichier.
Syntaxe :
Les fonctions locales sont une succession de blocs fonctionnels contenus dans un fichier maFonction.m portant le nom de la fonction principale maFonction :
function [s_1 ... s_ns] = maFonction(e_1... e_ne) instructions ; end function [s_1 ... s_ms] = uneFonctionLocale(e_1... e_me) instructions ; end function [s_1 ... s_ps] = uneSecondeFonctionLocale(e_1... e_pe) instructions ; end
Exemple :
Dans l'exemple qui suit, nous définissons une fonction tribulle.m dont l'objectif est de trier un vecteur de valeurs, en ordre croissant ou décroissant. Cette fonction a vocation à être utilisée et ré-utilisée, l'écriture d'une telle fonction se justifie pleinement.
Pour définir cette fonction, nous avons décidé de séquencer notre code en sous-fonctions. Ces sous-fonctions sont utiles à la fonction tribulle, mais n'ont pas d'utilité en dehors de ce contexte, c'est pourquoi nous les avons définies comme sous-fonctions et non comme des fonctions spécifiques dans d'autres fichiers .m.
%% tribulle.m
% Fabien Baillon et Jean-Louis Dirion - Novembre 2014
%
% Cette fonction permet de trier un ensemble de valeurs.
% V est le vecteur de valeurs à trier.
%
% ordre est un caractère :
% s'il vaut 'c', le tri sera par ordre croissant,
% s'il vaut 'd', le tri sera par ordre décroissant.
%
% La méthode utilisée pour ordonner le vecteur V est le tri par bulle.
function V = tribulle(V,ordre)
continu = true;
while(continu)
tri = false;
switch ordre
case 'c'
[V,tri] = trier_c(V,tri);
case 'd'
[V,tri] = trier_d(V,tri);
end
continu=tri;
end
end
function [V,tri] = trier_c(V,tri)
%% trier_c
%
% sous-fonction pour le tri croissant
for indice=1:length(V)-1
if(V(indice) > V(indice+1))
[V,tri] = permute(V,indice);
end
end
end
function [V,tri] = trier_d(V,tri)
%% trier_d
%
% sous-fonction pour le tri décroissant
for indice=1:length(V)-1
if(V(indice) < V(indice+1))
[V,tri] = permute(V,indice);
end
end
end
function [V,tri] = permute(V,indice)
%% permute
%
% sous-fonction pour permuter les deux valeurs consécutives d'un vecteur
tmp = V(indice);
V(indice) = V(indice+1);
V(indice+1) = tmp;
tri = true;
end
trier_c, trier_d et permute sont des fonctions locales. Elles ne sont utilisables que dans le contexte de la fonction tribulle.
Remarque :
L'ordre des fonctions n'a aucune importance. Les sous-fonctions et la fonction principale peuvent être définies dans n'importe quel ordre, du moment qu'elles sont effectivement dans le même fichier.
Remarque :
On peut accéder à l'aide des sous-fonctions grâce à l'opérateur > :
>> help tribulle>permute permute sous-fonction pour permuter les deux valeurs consécutives d'un vecteur
Remarque :
Il existe une fonction prédéfinie qui s'appelle aussi permute, cette fonction ne fait pas du tout la même chose que notre fonction locale : la fonction prédéfinie est une fonction qui permute les dimensions des tableaux, c'est une généralisation de la transposition.
Par définition, les fonctions locales n'ont une existence qu'au sein de la fonction principale. Le fait que l'on définisse une fonction locale ayant un nom identique à une fonction pré-existante ne pose aucun problème, parce que l'on n'a pas besoin de la fonction permute pré-définie !
La fonction locale est toujours prioritaire par rapport à une fonction externe, pré-définie ou non, ayant le même nom.
Fonction imbriquée
Les fonctions imbriquées sont un autre type de sous-fonctions.
Syntaxe :
Une fonction imbriquée est un bloc fonctionnel contenu dans un autre bloc fonctionnel, correspondant à une fonction ou une fonction locale :
function [s_1 ... s_ns] = maFonction(e_1... e_ne) instructions ; function [s_1 ... s_ls] = uneFonctionImbriquee(e_1... e_le) instructions ; end end function [s_1 ... s_ms] = uneFonctionLocale(e_1... e_me) instructions ; function [s_1 ... s_ps] = uneAutreFonctionImbriquee(e_1... e_pe) instructions ; end end
Exemple :
Nous avons ré-écrit l'exemple tribulle, en utilisant maintenant des fonctions imbriquées. Dans cette nouvelle version, la fonction tribulle_versionImbriquee contient une sous-fonction imbriquée trier, qui elle-même contient une sous-fonction imbriquée permute :
%% tribulle_versionImbriquee.m
% Fabien Baillon et Jean-Louis Dirion - Novembre 2014
%
% Cette fonction permet de trier un ensemble de valeurs.
% V est le vecteur de valeurs à trier.
%
% ordre est un caractère :
% s'il vaut 'c', le tri sera par ordre croissant,
% s'il vaut 'd', le tri sera par ordre décroissant.
%
% La méthode utilisée pour ordonner le vecteur V est le tri par bulle.
function V = tribulle_versionImbriquee(V,ordre)
continu = true;
while(continu)
trier();
end
function [] = trier()
%% trier
%
% sous-fonction pour le tri
continu = false;
for indice=1:length(V)-1
switch ordre
case 'c'
if(V(indice) > V(indice+1)) permute(); end
case 'd'
if(V(indice) < V(indice+1)) permute(); end
end
end
function [] = permute()
%% permute
%
% sous-fonction pour permuter les deux valeurs consécutives d'un vecteur
tmp = V(indice);
V(indice) = V(indice+1);
V(indice+1) = tmp;
continu = true;
end
end
end
Remarque :
Les fonctions sont imbriquées, de ce fait les sous-fonctions ont accès aux variables définies dans la fonction ou la sous-fonction qui les englobe.
C'est pourquoi les variables ne sont plus passées en argument des sous-fonctions, car ce n'est pas nécessaire ici. Contrairement aux fonctions locales, les fonctions imbriquées partagent le même espace mémoire (workspace).
Remarque :
Les sous-fonctions n'ont pas de variables d'entrée et de sortie, car ici, ce n'est plus nécessaire. De ce fait, on aurait pu ne pas indiquer de vecteur de sortie, et ne pas mettre de parenthèses, lors de la définition des sous-fonctions, en écrivant par exemple :
function trier
Cependant, nous préférons les mettre malgré tout, pour indiquer explicitement qu'il n'y a pas d'entrée et de sortie (ce n'est pas un oubli !) :
function [] = trier()