Étudions ce qui se passe lorsqu'on appelle une fonction avec des arguments. Prenons une fonction a au moins deux arguments, qui réalise une tâche quelconque. Par exemple l'affichage de la somme des deux paramètres :
let f x y = print_int (x + y); in f (3+2) (6-5);
Question très intéressante : calcul-t-on d'abord (3+2)
ou (6-5)
? Ajoutons des opérations d'affichage pour le savoir :
let f x y = print_int (x + y); in f (print_string "calcul a\n"; 3+2) (print_string "calcul b\n"; 6-5);
calcul b calcul a 6
Conclusion : contrairement à l'ordre naturel, on calcul d'abord le second argument. Mais aucune règle ne garanti que ça restera comme ça.
Les arguments d'une fonction sont tous évalués avant l'exécution de la fonction. L'ordre d'évaluation des arguments n'est pas spécifié
.Comment faire pour forcer un ordre particulier de calcul ? C'est très simple, on utiliser des let
pour nommer les arguments. Dans notre exemple, on ferai :
let a = 3+2 in let b = 6-5 in f a b ;La preuve :
let a = (print_string "calcul a\n"; 3+2) in let b = (print_string "calcul b\n"; 6-5) in f a b;
calcul a calcul b 6
Pour préciser un ordre de calcul des arguments lors de l'application d'une fonction, on les définit auparavant avec un let
dans l'ordre souhaité
On va maintenant reprendre la fonction récursive factorielle
et rajouter des fonctions d'affichage afin de bien suivre la création et la destruction de tous les robots utilisés dans le processus. Ainsi on affiche i
suivi de "début"
lorsqu'un robot chargé de calculé factorielle i
est mis en route, et i
suivi de "fin"
lorsque ce robot s'apprête à déposer son résultat et à s'auto-détruire. Comme déposer la valeur de retour est la dernière chose que fait un robot dans sa vie, on est obliger de nommer d'abord le résultat, pour avoir le temps d'afficher "fin"
avant de retourner ce résultat.
let rec factorielle n = print_int n; print_string " debut\n"; let resultat = if n = 1 then 1 else n * (factorielle (n-1)) in print_int n; print_string " fin\n"; resultat in print_int (factorielle 3);
3 debut 2 debut 1 debut 1 fin 2 fin 3 fin 6