Objective Caml/Bases
Objectifs du chapitre.
Ce chapitre vous enseignera
À l'issue de ce chapitre, vous pourrez utiliser OCaml comme une super-calculatrice programmable.
Matériel nécessaire pour ce chapitre.
Pour ce qui suit, vous allez avoir besoin d'une installation d'Objective Caml 3.11 ou ultérieur avec Batteries Included et peut-être de quelques outils. Objective Caml est disponible sur de nombreuses plate-formes.
"Note" Il est fort probable que tout ce qui suit fonctionne aussi avec une version plus ancienne de OCaml. Ceci n'a pas été testé.
Power Users (Linux, MacOS X, BSD, Cygwin).
Si la notion de dépendances et l'idée d'installer des logiciels en ligne de commande ne vous pose pas de problèmes,
la méthode recommandée est d'utiliser la distribution GODI d'OCaml, disponible sous toutes les plate-formes
Unix, Windows y compris (par le biais de la couche Unix Cygwin).
Toutes les plate-formes.
Tout ce qui suit doit se dérouler sous votre compte utilisateur courant. 
vim ~/.bash_profile
afin d'ajouter les lignes suivantes:
 if [ -d ${HOME}/godi/bin -a -d ${HOME}/godi/sbin ] ; then 
 fi
 if [ -d ${HOME}/godi/man ] ; then
 fi
 # Spécifique Windows + Cygwin
 TTY=`tty`
N.B.: Étendre la variable $PATH en rajoutant les chemins des binaires produit par l'installation de GODI est une bonne idée, peu importe le shell et l'OS ;-)
./bootstrap --prefix <PREFIX> --section=3.12
(remplacez codice_1 par le chemin complet vers le répertoire dans lequel vous souhaitez installer GODI).
les commandes suivantes :
PATH=$PATH:<PREFIX>/bin:<PREFIX>/sbin; export PATH
./bootstrap_stage2
Une fois l'installation de GODI terminée, vous pourrez ajouter des bibliothèques OCaml en tapant
godi_console perform -build godi-batteries
pour installer Batteries Included par exemple.
Spécifique à Cygwin.
Sous Windows™, la commande permettant l'initialisation du bootstrap installe le portage pour Cygwin (vos applications auront besoin de cygwin.dll pour fonctionner). 
Il faudra néanmoins faire un 
 export PATH=/usr/local/bin:/usr/bin
avant cette commande pour ne pas avoir d'espaces dans les chemins de la variable $PATH. 
Pour avoir une installation qui fonctionne sans Cygwin, il faut spécifier un autre portage sur la ligne de commande.
Spécifique à MinGW32.
Pour MinGW32 (à installer par Cygwin), installer d'abord gcc et ensuite gcc-mingw en version 3.
Et ensuite remplacer la commande d'initialisation du bootstrap par:
 export PATH=/usr/local/bin:/usr/bin
./bootstrap --prefix <PREFIX> --section=3.12 --w32port=mingw
Attention: le portage pour MinGW32 permet générer des binaires natifs pour Windows™ plus rapide mais au prix d'avoir quelques appels systèmes en moins et d'avoir un certain nombre de soucis avec les chemins.
Alternative, sous Unix.
Des paquets pour OCaml sont disponibles pour :
Vous pouvez les trouver à l'aide des mécanismes habituels de gestion de paquets de votre distribution.
En plus de ce qui précède, il est recommandé d'installer soit le logiciel codice_2 (disponible sous GODI),
soit le logiciel codice_3 (disponible sous votre gestionnaire de paquets), qui vous simplifieront le
travail lors de l'utilisation d'OCaml en ligne de commande.
Alternative, sous Windows.
La distribution minimale pour Windows, avec un installateur graphique, est disponible sur le site officiel. Insistons sur le fait que cette distribution est minimale et donc peu utilisable.
Le mode calculatrice d'OCaml.
OCaml dispose de deux modes principaux d'utilisation :
C'est ce dernier que nous allons utiliser le temps d'un chapitre. Ce mode calculatrice, bien que limité par rapport à un compilateur et beaucoup plus lent que le compilateur-optimisateur d'OCaml, est très pratique pour tester des extraits de code ou lancer des calculs.
Pour lancer ce mode calculatrice, la manière la plus simple minimale est d'ouvrir un terminal puis de taper
ocaml
mais l'édition et les fonctions de bases sont alors limitées, il est donc recommandé d'utiliser plutôt
rlwrap ocamlfind batteries/ocaml
ou, si vous avez installé ledit au lieu de rlwrap, 
ledit ocamlfind batteries/ocaml
Cette instruction demande à votre système d'exploitation de trouver et d'exécuter la version de OCaml Batteries Included installée sur votre ordinateur. Sur cette ligne, codice_4 est le gestionnaire de versions de OCaml et des bibliothèques OCaml, qui permet de manipuler diverses versions de OCaml, codice_5 est le nom du mode calculatrice d'OCaml avec Batteries Included et codice_3/codice_2 est un petit outil qui simplifie l'édition de texte.
Premiers pas avec OCaml.
À l'ouverture en mode calculatrice OCaml affiche le message suivant :
La première ligne confirme que OCaml 3.12 a bien été chargé. La suite confirme que vous utilisez bien OCaml Batteries Included et non pas une distribution plus minimaliste de OCaml. Enfin, le symbole codice_8 est l'invite de commande, qui signifie que la ligne de commande est prête et attend vos instructions. Au cours de ce chapitre, nous ferons figurer ce symbole au début de chaque ligne tapée par l'utilisateur. Insistons sur le fait que c'est à OCaml d'afficher ce symbole et non pas à vous de le taper.
Note Si jamais vous avez besoin d'interrompre un programme en cours d'exécution dans la calculatrice, utilisez la combinaison de touches codice_9. Si vous avez besoin de quitter la calculatrice, écrivez codice_10.
La ligne de commande accepte
Pour commencer, intéressons-nous aux évaluations. 
Calculer avec OCaml.
Pour évaluer 0 + 1, écrivons
Le symbole codice_11 constitue la "fin de phrase". Dans la calculatrice, chaque évaluation doit être suivie d'une fin de phrase.
Convention Les conventions syntaxiques de OCaml veulent qu'on insère une espace avant l'opérateur et une espace après l'opérateur. Ces conventions évitent certaines erreurs de relecture de programmes lors de l'utilisation d'opérateurs personnalisés. On insèrera de même une espace avant et après chaque parenthèse.
L'expression arithmétique précédente produira la réponse
- : int = 1
Cette réponse se lit "le résultat du dernier calcul est un entier, sa valeur est 1". Nous reviendrons plus tard sur la définition des entiers en OCaml.
OCaml dispose des opérations arithmétiques habituelles sur les entiers : addition (codice_12), soustraction (codice_13), multiplication (codice_14), division entière (codice_15), reste de la division entière (codice_16), négation (codice_17), avec les priorités mathématiques habituelles. Tous ces opérateurs sont infixes. Ainsi, on écrira
- : int = 2
Notons que toutes ces opérations acceptent uniquement des entiers et produisent uniquement des entiers. Ainsi, on obtiendra
- : int = 0
De même, OCaml dispose des opérations arithmétiques habituelles sur les nombres à virgule : addition (codice_18), soustraction (codice_19), multiplication (codice_20), division (codice_21), puissance (codice_22). Ces opérations, de nouveau, sont infixes et respectent les priorités mathématiques habituelles. On écrira donc
- : float = 8
De nouveau, toutes ces opérations acceptent uniquement des nombres à virgule flottante et renvoient uniquement des nombres à virgule flottante. Si l'on tente de combiner entiers et nombres à virgule flottante, on obtiendra
This expression has type float but is here used with type int
This expression has type int but is here used with type float
Note En cas d'erreur de syntaxe ou la compilation, OCaml souligne la zone sur laquelle porte l'erreur à l'aide soit de symboles ^^^, soit de traits, selon l'environnement utilisé, voire la surligne en couleur. Il arrive malheureusement que les symboles soient décalé de quelques caractères.
Pour mélanger entiers et nombres à virgule, on emploie les fonctions de conversion codice_23 et codice_24.
- : float = 0.666666666667
- : int = 2
Quelques autres fonctions complètent l'attirail :
Pour consulter la documentation sur chacune de ces fonctions, utilisez la directive codice_33, comme suit :
Limitations et précautions.
Limites de calcul.
Comme dans la majorité des langages de programmation, les entiers sont bornés par la capacité de calcul du microprocesseur. Avec OCaml, sur un ordinateur à processeur 32 bits, les limites sont de
- : int = -1073741824
- : int = 1073741823
c'est-à-dire formula_1. 
Sur un ordinateur à processeur 64 bits, les limites sont de 
- : int = -4611686018427387904
- : int = 4611686018427387903
c'est-à-dire formula_2.
Note pour lecteurs avancés : à la lecture, un programmeur habitué aux limites des systèmes s'interrogera sur le destin du dernier bit. Celui-ci sert à différencier les 'entiers' et les 'références' lors de la récupération de la mémoire vive. Cette astuce limite la gamme des entiers utilisables sur le système mais évite 
Pour les applications ayant besoin d'une gamme d'entiers plus grande que ce que OCaml propose par défaut, plusieurs alternatives existent. Notamment, OCaml est fourni avec une bibliothèque de calcul sur 64 bits et une bibliothèque de calculs sur entiers de taille illimitée. D'autres bibliothèques sont disponibles, pour faire face à d'autres circonstances.
Dépassements de capacité.
Par défaut, les opérations arithmétiques sur les entiers ne préviennent pas en cas de dépassement. Ainsi, on aura
- : int = 1073741823
Il est possible de modifier la définition des opérations arithmétiques de manière à prévenir (lancer une exception) en cas de dépassement mais la solution est lente et reste imparfaite. Nous verrons ultérieurement comment demander à OCaml Batteries Included d'utiliser cette version des opérations.
Conversion automatique.
Un entier n'est pas un nombre flottant et un nombre flottant n'est pas un entier. Il a été plusieurs fois question de permettre en OCaml la conversion automatique d'un entier en un flottant ou d'un flottant en entier, comme dans certains autres langages de programmation, mais les développeurs d'OCaml ont rejeté l'idée, pour plusieurs raisons :
À retenir.
signale une erreur de typage : l'analyse de type a déterminé que l'expression soulignée porte le type codice_38, alors que le contexte dans lequel elle est utilisée est prévu uniquement pour des valeurs de type codice_39.
Booléens.
Deux entiers ou deux nombres à virgule peuvent être comparés à l'aide des opérateurs codice_40, codice_41, codice_42 et codice_43, codice_44, codice_45, codice_46.
- : bool = false
- : bool = false
This expression has type int but is here used with type float
Note : l'opérateur codice_40 procède à une comparaison au sens mathématique du terme (comparaison structurelle) et non au sens de l'identité (égalité des références), contrairement à ce qui se produit dans l'essentiel des langages de programmation, et ne dépend pas de l'éventuelle codice_48-ité d'un pointeur. En d'autres termes, si vous avez besoin de vérifier l'égalité de deux valeurs, et à moins d'avoir une très bonne raison de changer la définition de l'égalité, vous pouvez utiliser sans crainte l'opérateur codice_40.
Le résultat d'une comparaison est une valeur codice_50 ou codice_51, de type codice_52.
Deux booléens peuvent eux-même être comparés à l'aide de l'opérateur codice_40 -- en fait, comme nous le reverrons plus loin, les opérateurs de comparaison peuvent être appliqués à n'importe quel couple de valeurs de même type. En plus de la comparaison, les booléens sont dotés des opérateurs et fonctions habituelles : le 'et logique' paresseux (codice_54), le 'ou logique' paresseux (codice_55) et la négation (codice_56).
Les booléens sont employés notamment dans les opérations de contrôle de flot (presque) habituelles d'OCaml :
- : int = 3
Nous reviendrons un peu plus tard sur ces instructions de contrôle de flot.
Déclaration de valeurs.
Valeurs simples.
Déclarer une valeur consiste à donner un nom au résultat d'une expression. Ainsi, l'extrait
val pi : float = 3.1415927
'lie', pour toute la suite de l'exécution du programme, le nom codice_61 à la valeur '3.1415927'.
La réponse d'OCaml se lit d'ailleurs "Dorénavant, le nom pi désigne un nombre flottant dont la valeur est 3.1415927."
Ce nom peut être réutilisé dans n'importe quelle expression :
- : float = -0.999948994965
Note : insistons sur le fait que la valeur de codice_61 ne peut changer.
Pour être plus précis, "il est possible de masquer codice_61 par une nouvelle définition mais pas de réaffecter une nouvelle valeur à codice_61". En d'autres termes, les valeurs OCaml fonctionnent comme les constantes dans de nombreux langages. On les appelle cependant des "variables", car il s'agit bien de variables au sens mathématique du terme.
Note : un nom lié est toujours "lié à une valeur". En d'autres termes, en OCaml, il n'est jamais nécessaire de vérifier si une valeur est codice_48, codice_66, etc. Dans les cas où il est nécessaire de manipuler une valeur qui peut ou non être définie, on emploiera le mécanisme des codice_67s, que nous verrons plus tard.
Tenter d'utiliser un nom qui n'est pas lié provoque une erreur. Ainsi, on aura
Unbound value pi'
Nous verrons plus tard que, comme les erreurs de type ou de syntaxe, les erreurs de liaison sont détectées à la compilation, comme en Java ou C# et par opposition à Python, JavaScript ou Ruby.
Bien entendu, un nom peut être donné au résultat d'une expression plus complexe que la constante 3.1415. Ainsi, pour définir codice_61, on utilisera plutôt le calcul plus précis suivant :
val pi : float = 3.14159265359
Note : La liaison codice_69 calcule immédiatement le résultat de l'expression. Si nécessaire, OCaml propose aussi des "expressions paresseuses", qui ne sont calculées que lorsque leur résultat est effectivement consulté. Nous en rediscuterons plus tard.
Plusieurs noms peuvent être définis simultanément
 and y = 2;;
val x : int = 1
val y : int = 2
val a : int = 1
val b : int = 2
Notons que le nom n'est lié qu'à partir de la fin de sa déclaration. En d'autres termes, à l'intérieur de la définition de codice_70, 
codice_70 n'a pas de sens :
Unbound identifier x
Il est aussi possible de lier un nom localement. Ainsi, on écrira
 3 * x * x + 4 * x + 5 = 0 ;;
- : bool = false
ou encore
 where x = 50;;
- : bool = false
Dans cet extrait, le nom codice_70 n'est lié que le temps de calculer codice_73 et de comparer ce résultat à codice_74. On dit que "la portée de codice_70" est codice_76. La réponse de OCaml, qui commence par un tiret, confirme qu'aucune nouvelle variable n'a été liée globalement par cette expression. Ainsi, essayer ensuite d'utiliser codice_70 hors de sa portée expression provoquera une erreur
Unbound value x
Unbound value x
Comme le montre notre exemple précédent, codice_78 est une expression et a donc un résultat. On peut donc combiner codice_79 et codice_80 de manière à donner un nom global au résultat d'un calcul qui utilise des noms locaux :
 let x = 50 in
 3 * x * x + 4 * x + 5 = 0 ;;
val y : bool = False
On peut de même définir des couples ou partager des valeurs entre plusieurs résultats de manière à éviter de les recalculer :
 let ( pi_1, pi_2 ) = 
 ( 2. *. acos ( 0. ), 2. *. asin ( 1. ) )
 in
 ( pi_1, abs_float ( pi_1 -. pi_2 ) );;
val valeur_de_pi : float = 3.14159265359
val incertitude_entre_valeurs : float = 0
Sans surprise, si une liaison globale peut contenir des liaisons locales et si une liaison locale peut elle-même contenir d'autres liaisons locales, une liaison globale a toujours lieu au plus haut niveau, jamais à l'intérieur d'une expression. En d'autres termes, un calcul ne peut pas avoir comme effet secondaire de faire apparaître une nouvelle liaison globale. Ce comportement est similaire à celui de Java ou C#, par opposition à celui de JavaScript, Python ou Ruby.
Ce mécanisme de liaison locale est utilisé notamment :
Note Un nom de variable commence toujours par une minuscule ou le caractère codice_83. Les identificateurs commençant par des majuscules sont réservées aux constructeurs et aux noms de modules, dont nous discuterons plus tard. Tenter d'utiliser un nom commençant par une majuscule en tant que variable provoque une erreur de syntaxe parfois difficilement lisibles.
Error: Unbound constructor Pi
Nous verrons plus tard ce que sont les constructeurs en OCaml.
À retenir.
signifie que le nom xxxxx n'est pas lié (ou défini) dans ce contexte.
Fonctions.
Syntaxe.
Dans ce qui précède, nous avons déjà manipulé quelques fonctions
- : float = 5
- : int = 5
En OCaml, les fonctions sont des valeurs comme les autres, qui peuvent être déclarées à l'aide de codice_84, manipulées, évaluées, passées en tant qu'argument ou qui peuvent elles-mêmes être le résultat de l'évaluation d'expressions ou d'autres fonctions. Pour définir une fonction, OCaml propose plusieurs syntaxes, entre lesquelles nous choisirons selon des critères essentiellement esthétiques :
 and ajouter_deux ( x ) = x + 2 
 and ajouter_trois x = x + 3 
 and (ajouter_quatre x) = x + 4;;
val ajouter_un : int -> int = <fun>
val ajouter_deux : int -> int = <fun>
val ajouter_trois : int -> int = <fun>
val ajouter_quatre : int -> int = <fun>
Avant de nous intéresser à la réponse d'OCaml, commençons par détailler ces quatre syntaxes. Notons aussi que nous aurions pu déclarer les quatre fonctions séparément ou sous la forme d'un quadruplet mais nous avons préféré utiliser codice_88 pour habituer le lecteur à lire et à utiliser cette construction.
Vocabulaire Dans ces fonctions, on appelle codice_70 "argument" ou "paramètre formel" de la fonction, codice_90 "corps de la fonction" et codice_91 "fonction anonyme", "abstraction" ou "λ-expression". Tout comme une valeur liée à l'aide de codice_79, l'argument codice_70 a une "portée" limitée au corps de la fonction. En fait, codice_70 est "lié" à l'intérieur de la fonction.
La première syntaxe fait appel au mot-clé codice_95 (pour "function") et s'énonce "Le nom "ajouter_un" est lié à la fonction qui à tout x associe x + 1", soit encore, en langage plus mathématique, formula_3. Cette formulation met l'accent sur le fait qu'une fonction est une valeur comme une autre.
La deuxième syntaxe s'énonce "Pour tout x, la valeur de codice_96 est x + 2", soit encore, en langage mathématique, formula_4." Le résultat est absolument équivalent à celui qu'on obtient avec la première syntaxe et le vocabulaire est le même, mais cette formulation met l'accent sur la présentation d'une fonction comme une famille de valeurs.
La troisième et la quatrième syntaxe sont des variantes sur la deuxième, et s'énoncent de la même manière. Nous nous sommes contentés de jouer sur le placement des parenthèses afin d'illustrer la signification de celles-ci. En effet, contrairement à la majorité des langages, dans lesquels il est obligatoire d'encadrer les arguments d'une fonction entre des parenthèse, en OCaml, ces dernières ne sont obligatoires que pour forcer les priorités et résoudre d'éventuelles ambiguïtés, tout comme les parenthèses dans une expression arithmétique ne sont obligatoires que pour forcer la priorité des opérations.
Note En OCaml, dans presque tous les cas, la syntaxe idiomatique est la plus courte. On définira donc généralement une fonction sous une forme proche de codice_97. 
Cette conception des parenthèses s'applique aussi lors de l'invocation de fonctions :
- : int = 22
- : int = 22
- : int = 22
- : int = 21
- : int = 22
- : int = 22
- : int = 22
This function is applied to too many arguments, maybe you forgot a `;'
Nous nous intéresserons à ce message d'erreur un peu plus tard. Pour le moment, contentons-nous d'en déduire qu'une fonction -- qui n'est, par définition, pas un nombre -- ne peut pas être multipliée par 2 à l'aide de l'opérateur codice_14.
Du reste de l'échantillon, nous pouvons déduire que "l'invocation de fonction est plus prioritaire que la multiplication" et que le parenthésage n'est nécessaire que pour forcer la priorité. 
Note En cas de doute sur la priorité des opérateurs et des opérations, ajoutez des parenthèses. C'est ce que font tous les programmeurs OCaml et ça évite bien des erreurs, surtout à partir du moment où vous définirez vos propres opérateurs.
Insistons sur le fait qu'une fonction est une valeur comme une autre. Ainsi, on peut parfaitement écrire une fonction dont le résultat est une autre fonction
 fun y ->
 x * y ;;
let multiplication : int -> int -> int = <fun>
Ce résultat se lit "Le nom codice_99 est lié à une fonction dont l'argument est un entier et dont le résultat est une fonction de l'ensemble des entiers vers l'ensemble des entiers." Cette fonction codice_99 se manipule naturellement :
val multiplication_par_5 : int -> int = <fun>
- : int = 50
En une seule étape, nous écririons
- : int = 50
- : int = 50
Vocabulaire Dans ce qui précède, une fonction de la forme codice_101 est appelée "clôture". Le terme désigne une fonction définie à l'intérieur d'une autre fonction et qui utilise des variables locales ou des arguments de la fonction qui la contient. On emploie parfois le terme (improprement) pour désigner n'importe quelle fonction locale.
De même, nous pouvons définir une fonction qui prend en argument une fonction et produit comme résultat une fonction :
 fun x ->
 fun y ->
 fun o ->
 o x y ;;
val appliquer_operation_postfixe : 'a -> 'b -> ('a -> 'b -> 'c) -> 'c = <fun>
- : int = 50
- : int = 10
Nous reviendrons sous peu sur la manipulation de fonctions par des fonctions et sur le sens de ce type codice_102.
Il est à noter que, tout comme une fonction peut être définie globalement à l'aide de codice_84, elle peut être définie localement avec codice_79.
Types.
Maintenant que nous avons examiné la syntaxe, revenons à la réponse de OCaml lors de la définition de chacune des fonctions :
val ajouter_un : int -> int = <fun>
val ajouter_deux : int -> int = <fun>
val ajouter_trois : int -> int = <fun>
val ajouter_quatre : int -> int = <fun>
La première ligne s'énonce "Nous venons de définir la valeur globale codice_118. Cette valeur est de type codice_119 et il s'agit d'une fonction, que nous n'afficherons pas." 
Note OCaml n'affichera jamais le contenu d'une fonction.
Plus en détail, le type codice_119 est le type des fonctions à un seul argument, qui est un entier, et dont le résultat est un entier. Mathématiquement, en considérant codice_34 comme l'ensemble des entiers OCaml, ce type signifie que la fonction est prise dans l'ensemble formula_6, ou encore formula_7. 
En Java, on écrirait :
public static int ...(int ...)
À l'inverse, en OCaml, c'est l'ordinateur qui détermine le type de la fonction en analysant ses arguments et son corps. Ici, l'analyseur de types a remarqué la présence d'une addition sur les entiers, qui détermine que codice_70, le seul argument de la fonction, est un entier et que le résultat de la fonction est un entier. La fonction est donc de type codice_119.
Vocabulaire Lorsqu'un analyseur de types déduit automatiquement le type des valeurs au lieu de recourir à des annotations, on appelle ce processus l'inférence de types.
On peut s'interroger sur le comportement de l'analyseur lorsqu'il est confronté à des contraintes différentes, par exemple des contraintes qui imposent que x soit à la fois un entier et un nombre flottant. Observons :
This expression has type int but is here used with type float
L'analyseur a conclu que le programme était erroné, puisqu'il partait à la fois du principe que codice_70 était un entier (pour additionner 1) et du principe que codice_70 était un nombre flottant (pour additionner 1.0). La réponse d'OCaml est donc que la fonction contient une erreur de types et que cette définition doit être refusée. En effet, on constate que codice_105 n'est pas définie :
Unbound value f
On peut aussi s'interroger sur le comportement de l'analyseur lorsque codice_70 n'est pas contraint. Observons :
val id : 'a -> 'a = <fun>
La réponse d'OCaml s'énonce "Nous venons de définir la valeur globale codice_128. Cette valeur est de type "pour tout type α, α -> α". Il s'agit d'une fonction."
Le type de la fonction codice_128 est dit "polymorphe sur le paramètre α". Ainsi, on pourra utiliser codice_128 sur des entiers, des booléens ou n'importe quel autre type de données, fonctions y compris.
- : int = 5
- : bool = true
- : float = 3.2
- : int -> int = <fun>
- : int -> int = <fun>
En Java ou C#, le polymorphisme paramétrique est connu sous le nom de "généricité" et est à la fois moins puissant, plus compliqué, plus lent, plus long à écrire et moins robuste que le polymorphisme paramétrique d'OCaml. Nous revisiterons fréquemment le polymorphisme, qui est présent à tous les niveaux d'OCaml, et qui constitue un outil puissant de réutilisation de code.
Note Dans le dernier exemple, nous avons passé comme argument à la fonction codice_128 la fonction codice_132 puis, plus tard, une λ-expression codice_91. Passer en argument des fonctions nommées ou anonymes est une pratique courante en OCaml. On s'en sert notamment pour les parcours de structures de données, les boucles, etc.
Exercices.
let multiplie n f = 
 fun x -> n * ( f x ) ;;
Arguments supplémentaires.
Jusqu'à présent, nous n'avons défini et manipulé que des fonctions acceptant un seul argument. Bien entendu, comme tous les autres langages de programmation, OCaml permet de manipuler des fonctions à plusieurs arguments.
En fait, ce n'est pas tout à fait vrai. Nous avons déjà manipulé une fonction à plusieurs arguments : la multiplication
- : int -> int -> int
Comme nous pouvons le remarquer, le type de codice_99 est codice_137. Nous l'avons lu "La fonction codice_99 accepte un argument de type codice_34 et produit un résultat qui est une fonction qui accepte à son tour un argument de type codice_34 et produit un résultat de type codice_34." De fait, ce type peut aussi se lire "La fonction codice_99 accepte deux arguments de type codice_34 et produit un résultat de type codice_34."
Si nous souhaitons définir une fonction dont l'effet sera identique à codice_99, nous pouvons de nouveau employer plusieurs syntaxes équivalentes :
val multiplication_2 : int -> int -> int = <fun>
val mutiplication_2 : int -> int -> int = <fun>
val multiplication_2 : int -> int -> int = <fun>
val multiplication_2 : int -> int -> int = <fun>
val multiplication : int -> int -> int = <fun>
La première syntaxe met en valeur le fait que codice_146 est une fonction à deux arguments dont le résultat est de multiplier ses arguments. La deuxième syntaxe met en avant le fait que codice_146 est une fonction à un argument dont le résultat est une fonction qui à son tour attend un argument avant de multiplier ces deux arguments. La troisième syntaxe insiste sur le fait que, pour tout codice_70, codice_149 est de nouveau une fonction qui à son tour attend un argument avant de multiplier cet arguments par codice_70. La quatrième syntaxe présente la famille des valeurs codice_151 pour tout entier codice_70 et tout entier codice_153, qui vaut alors codice_154. Enfin, la dernière formulation présente le fait que codice_146 est la même opération que codice_99.
Ces quatre syntaxes sont presque équivalentes et tout aussi valables. Comme précédemment, on préfèrera la plus courte, c'est-à-dire ici la dernière. Lorsqu'un tel raccourci n'est pas possible, on se rabattra sur la syntaxe précédente.
Insistons donc sur un fait : en OCaml, "une fonction à plusieurs arguments est une fonction à un argument et dont le résultat est encore une fonction".
L'une des conséquences de cette conception des fonctions et qu'il est possible, avec une fonction à plusieurs arguments, de pré-appliquer la fonction certaines des valeurs de manière à obtenir une fonction spécialisée. Ainsi, on pourra écrire
- : int -> int = <fun>
- : int = 8
Vocabulaire La transformation d'une fonction à "n" arguments en une fonction à "n-1" arguments s'appelle la "currification". C'est une technique fréquemment employée en OCaml. Elle permet de composer aisément des fonctions et sert notamment pour construire aisément des fonctions à passer en argument à d'autres fonctions. Nous y reviendrons sous peu.
Une autre conséquence de cette conception des fonctions est qu'il n'existe pas, en OCaml, de fonction sans arguments. Nous reviendrons sur ce point un peu plus tard.
Fonctions et opérateurs.
Avant d'approfondir notre étude des fonctions et d'introduire la notion de récursivité, arrêtons-nous un instant sur la définition des opérateurs. Tout comme en C++ ou en Python, en OCaml, les opérateurs sont en fait des fonctions. Ainsi, chaque utilisation de l'opérateur codice_14 est en fait un appel à la fonction codice_169 (les espaces et les parenthèses font partie du nom de la fonction), chaque utilisation de codice_12 est un appel à la fonction codice_171...
Nous pouvons donc écrire
- : int -> int -> int = <fun>
- : int = 50
- : float = 3.6
- : bool = False
val multiplication : int -> int -> int = <fun>
Vocabulaire L'opérateur codice_14 est la "forme infixe" de la multiplication alors que la fonction codice_169 est la "forme préfixe" de la multiplication. De base, en OCaml, il n'existe pas de "formes postfixes".
En fait, lorsque l'analyseur syntaxique d'OCaml rencontre une expression de la forme codice_154, celle-ci est comprise comme l'appel de fonction codice_175. Ceci est important à savoir pour plusieurs raisons :
Ainsi, revenons à l'erreur que nous avons rencontrée plus tôt :
This function is applied to too many arguments, maybe you forgot a `;'
On pourrait s'attendre à ce que codice_176 provoque une erreur d'analyse de type -- rappelons que l'opérateur codice_14 ne concerne que des entiers et que codice_118 n'est visiblement pas un entier. On peut aisément confirmer que la multiplication d'une fonction par deux n'est pas légale :
This expression has type int -> int but is here used with type int
Cependant, ce n'est pas l'erreur que nous rapporte OCaml. En fait, pour comprendre ce message, il faut se souvenir que l'extrait 
( 2 * ajouter_un ) 10
est compris comme
( ( * ) 2 ajouter_un ) 10
ou encore, en supprimant les parenthèses inutiles,
( * ) 2 ajouter_un 10
En d'autres termes, la fonction codice_169 est bien appliquée à trois arguments, codice_180, codice_118 et codice_182. Comme la fonction codice_169 n'accepte que deux arguments, l'erreur rencontrée par OCaml est effectivement une erreur sur le nombre d'arguments.
Récursivité.
De nombreuses fonctions mathématiques et informatiques nécessitent la répétition d'une opération un grand nombre de fois ou jusqu'à ce qu'une condition soit remplie. Ainsi, pour calculer le "n"ème terme d'une suite définie par récurrence, on aura souvent besoin de commencer par calculer tous les termes précédents. De même, pour chercher numériquement la limite d'une fonction ou d'une suite, on aura souvent besoin de répéter des approximations jusqu'à obtenir deux termes successifs suffisamment proches, ou pour calculer le contour de l'ensemble de Mandelbrot, on répétera des calculs complexes un nombre limité de fois ou jusqu'à avoir dépassé un module donné. Du côté informatique du terme, pour traiter un grand nombre d'informations en provenance d'un périphérique tel que le clavier ou un capteur, on appliquera une fonction à chaque information reçue jusqu'à l'arrivée d'un contre-ordre ou d'un changement de configuration. Enfin, pour de nombreux problèmes mathématiques et informatiques, chercher la solution nécessite de se ramener constamment à des sous-problèmes de plus en plus simples jusqu'à être confronté à des questions élémentaires. C'est ainsi que l'on trouve la solution à des problèmes de recherche de chemins dans des cartes géographiques (méthode A* hiérarchique), qu'on calcule la valeur d'une expression arithmétique ou logique complexe, qu'on localise une valeur dans un arbre ou qu'on analyse les interactions entre corps célestes dans une approximation numérique du problème des n corps par quad-trees.
Tous ces comportements se traitent de la même manière. Dans la majorité des langages de programmation, on emploie les boucles impératives codice_184 et codice_185 ou codice_186 -- nous laisserons provisoirement de côté les boucles codice_187 et autres "compréhensions" présentes dans certains langages récents dont OCaml Batteries Included. En Objective Caml, si tous ces mécanismes sont disponibles, nous allons commencer par étudier le mécanisme plus général de "récursivité", qui reprend en informatique les notions mathématiques de récurrence et d'induction structurelle.
Le principe de la récursivité est simple : 
En pratique, on considérera plutôt l'approche suivante :
Illustrons ceci par le calcul de la somme des nombres de m à n :
En OCaml, cette définition se traduira par
 if n < m then
 0
 else
 m + ( somme_des_nombres ( m + 1 ) n ) ;;
val somme_des_nombres : int -> int -> int = <fun>
- : int = 15
Le mot-clé codice_188 introduit une fonction récursive, c'est-à-dire donc une fonction qui peut s'appeler elle-même. Sans ce codice_188,
codice_190 ne serait pas lié à l'intérieur du corps de la fonction. On obtiendrait donc :
 if n < m then
 0
 else
 m + ( somme_faux ( m + 1 ) n ) ) ;;
Unbound value somme_faux
Attardons-nous un moment sur l'évaluation de codice_191. Pour obtenir des détails sur l'utilisation d'une fonction, la ligne de commande OCaml dispose de l'instruction codice_192 :
somme_des_nombres is now traced.
somme <-- 1
somme --> <fun>
somme* <-- 3
somme <-- 2
somme --> <fun>
somme* <-- 3
somme <-- 3
somme --> <fun>
somme* <-- 3
somme <-- 4
somme --> <fun>
somme* <-- 3
somme* --> 0
somme* --> 3
somme* --> 5
somme* --> 6
- : int = 6
Cette réponse sera plus compréhensible avec quelques annotations :
somme <-- 1 (* pour ce faire, évaluons somme 1 *)
somme --> <fun> (* le résultat est une fonction *)
somme* <-- 3 (* évaluons ce résultat appliqué à 3 *)
 (* l'évaluation de somme 1 3 commence *)
 (* cette évaluation fait appel à la valeur somme 2 3 *)
 (* Début de l'évaluation de somme 2 3 *)
 somme <-- 2 (* Évaluons donc somme 2 *)
 somme --> <fun> (* le résultat est une fonction *)
 somme* <-- 3 (* évaluons ce résultat appliqué à 3 *)
 (* l'évaluation de somme 2 3 commence *)
 (* cette évaluation fait appel à la valeur somme 3 3 *)
 (* Début de l'évaluation de somme 3 3 *)
 somme <-- 3 (* Évaluons donc somme 3 *)
 somme --> <fun> (* le résultat est une fonction *)
 somme* <-- 3 (* évaluons ce résultat appliqué à 3 *)
 (* l'évaluation de somme 3 3 commence *)
 (* cette évaluation fait appel à la valeur somme 4 3 *)
 (* Début de l'évaluation de somme 4 3 *)
 somme <-- 4 (* Évaluons donc somme 3 *)
 somme --> <fun>(* le résultat est une fonction *)
 somme* <-- 3 (* évaluons ce résultat appliqué à 3 *)
 (* l'évaluation de somme 3 3 commence *)
 (* Nous avons toutes les informations nécessaires pour évaluer somme 4 3 *)
 somme* --> 0 (* Le résultat de cette évaluation est 0 *)
 (* Fin de l'évaluation de somme 4 3 *)
 (* Nous avons toutes les informations nécessaires pour évaluer somme 3 3 *)
 somme* --> 3 (* Le résultat de cette évaluation est 3 + 0, soit 3 *)
 (* Fin de l'évaluation de somme 3 3 *)
 (* Nous avons toutes les informations nécessaires pour évaluer somme 2 3 *)
 somme* --> 5 (* Le résultat de cette évaluation est 2 + 3, soit 5 *)
 (* Fin de l'évaluation de somme 2 3 *)
 (* Nous avons toutes les informations nécessaires pour évaluer somme 1 3 *)
somme* --> 6 (* Le résultat de cette évaluation est 1 + 5, soit 6 *)
- : int = 6
Ainsi, pour évaluer codice_193, OCaml aura commencé par se ramener au cas codice_194 puis au cas codice_195 puis encore au cas codice_196, qui lui se calcule directement. À partir du résultat de 
codice_196, il est aisé de reconstruire le résultat de codice_198, qui lui-même permet de reconstruire aisément le résultat de codice_199, qui lui-même permet de reconstruire aisément le résultat de codice_200.
Note En termes d'expressivité, le mécanisme de récursivité est exactement aussi puissant que les boucles impératives présentes dans la majorité des langages de programmation. En pratique, il est plus simple de traduire un programme écrit à l'aide d'une boucle impérative en un programme écrit à l'aide d'une boucle récursive que de faire la manipulation inverse. En effet, dans la majeure partie des cas, implanter un algorithme récursif à l'aide d'une boucle impérative nécessite de manipuler des structures de piles contenant elles-même des structures de données peu lisibles.
Notre boucle récursive n'a pas à être déclarée au plus haut niveau. On peut aussi la cacher à l'intérieur de la fonction, à l'aide de codice_79. Ainsi, en appelant codice_202 la boucle récursive, on obtiendra :
 let rec aux m' n' =
 if n' < m' then
 0
 else
 m' + ( aux ( m' + 1 ) n' ) ) 
 in
 aux m n;;
val somme : int -> int -> int = <fun>
Comme nous pouvons l'observer dans ce qui précède, à chaque appel récursif de codice_202, le nom codice_204 reste lié à la valeur de codice_205. Ainsi, au lieu d'utiliser codice_204, nous pouvons donc utiliser directement codice_207. Nous obtenons alors
 let rec aux m' =
 if n < m' then
 0
 else
 m' + ( aux ( m' + 1 ) n ) ) 
 in
 aux m;;
val somme : int -> int -> int = <fun>
Notons que le nom codice_208 tient ici un rôle similaire à celui d'une variable compteur codice_209 dans une boucle impérative codice_210. Notons aussi que, dans cet exemple, l'intérêt principal d'avoir transformé la définition pour faire intervenir une boucle codice_202 est de se débarrasser des arguments inutiles (ici codice_204). Dans des programmes complexes, il sera fréquemment utile de faire intervenir des fonctions/boucles de cette forme.
Note La somme des nombres de 1 à n peut très bien s'écrire en une seule ligne à l'aide de codice_213. Cette deuxième méthode est plus succinte et plus lisible mais fait appel à des concepts plus avancés et que nous ne rencontrerons que dans un chapitre ultérieur.
La structure employée sera la même lorsque nous chercherons à définir la fonction factorielle. Rappelons que, mathématiquement, la factorielle peut se définir par récurrence sur l'ensemble des entiers par
On écrira donc de même
 if n = 0 then 1
 else n * ( factorielle ( n - 1 ) ) ;;
val factorielle : int -> int = <fun>
- : int = 120
Ce que nous pourrons aussi réécrire en cachant la boucle
 let rec aux n' =
 if n' = 0 then 1
 else n * ( aux ( n - 1 ) ) 
 in aux n ;;
val factorielle : int -> int = <fun>
- : int = 120
Dans les exemples qui précèdent, nous nous sommes toujours ramenés à un cas plus simple en incrémentant et en décrémentant un entier de 1, à l'image d'une boucle codice_184. Bien entendu, la récursivité ne se limite pas à ce type de cas. Ainsi, l'algorithme d'exponentiation rapide, qui permet de calculer formula_8 sans procéder à codice_205 multiplications, emploie une structure légèrement plus compliquée.
La définition mathématique de cet algorithme est la suivante :
Rappelons que la notation "2k" signifie "un nombre pair "n" pour lequel nous noterons "k = n/2". De même, "2k+1" signifie "un nombre impair "n" pour lequel nous noterons "k = (n-1)/2"." Cette définition se traduit par
En OCaml, on écrira donc :
 if n = 0 then 1
 else 
 if n mod 2 = 0 then let x = puissance a ( n / 2 ) in x * x
 else let x = puissance a ( n / 2 ) in x * x * a ;;
val puissance : int -> int -> int = <fun>
En fait, on préfèrera modifier légèrement cette définition pour calculer codice_70 et codice_217 une seule fois :
 if n = 0 then 1
 else 
 let x = puissance a ( n / 2 ) in
 let y = x * x in
 if n mod 2 = 0 then y
 else y * a;;
val puissance : int -> int -> int = <fun>
Notons que la récursivité ne se limite pas à "une" fonction s'appelant elle-même. Ainsi, lors de l'analyse de langages de programmation, voire de langages humains, il est courant de se retrouver confronté à des dizaines ou des centaines de fonctions "mutuellement récursives". Nous rencontrerons cec genre d'exemple à la fin du prochain chapitre. Pour le moment, nous nous contenterons d'une méthode extraordinairement complexe pour déterminer la parité d'un nombre positif :
 and impair n = n <> 0 && ( n = 1 || pair ( n - 1 ) ) ;;
val pair : int -> bool = <fun>
val impair : int -> bool = <fun>
- : bool = false
- : bool = true
Le mécanisme de récursivité reviendra à tous les niveaux dans OCaml.
Exercice.
Rappelons que la notation mathématique "2m" signifie "un nombre pair p pour lequel nous noterons m = p/2", et "2m+1" signifie "un nombre impair i pour lequel nous noterons m = (i-1)/2".
Réutilisation de fonctions.
De la même manière que nous avons défini la somme des nombres entre codice_207 et codice_205, nous pouvons définir le produit des nombres entre ces bornes :
 if n <= m then 1
 else m * ( produit_des_nombres ( m + 1 ) n ) ) ;;
val produit_des_nombres : int -> int -> int = <fun>
En tout et pour tout, nous avons changé 
Face à ces deux fonctions extrêmement proches, le réflexe du programmeur OCaml sera de chercher comment écrire une seule fonction qui pourra être spécialisée pour devenir l'une ou l'autre. C'est le processus d'abstraction, qui à la source de la réutilisation de code et du développement de bibliothèques puissantes de programmation. 
Note Le terme de "patrons de conception" (design patterns) n'existe pas en programmation fonctionnelle. Cependant, s'il existait, le processus d'abstraction figurerait en deuxième place dans la liste des patrons de conception, juste après le développement de fonctions polymorphes paramétriques.
Pour écrire une telle fonction, 
La transformation produit donc :
 if n <= m then v
 else f m ( operation_sur_intervalle f v ( m + 1 ) n ) ;;
val operation_sur_intervalle : (int -> 'a -> 'a) -> 'a -> int -> int -> 'a =
 <fun>
ou encore
 let rec aux m' =
 if n <= m' then v
 else f m' ( aux ( m' + 1 ) )
 in aux m;;
À partir de là, nous pouvons obtenir de nouveau la somme et le produit des nombres en appliquant directement notre
nouvelle fonction (rappelons que codice_171 et codice_169 sont les fonctions correspondant aux opérateurs
codice_12 et codice_14) :
val somme_des_nombres_2 : int -> int -> int = <fun>
val produit_des_nombres_2 : int -> int -> int = <fun>
À ce prix-là, nous pouvons définir en une ligne la fonction factorielle, la somme des carrés des entiers...
val factorielle_2 : int -> int = <fun>
val somme_des_carres_2 : int -> int -> int = <fun>
On peut aussi construire à partir de codice_235 des fonctions similaires qui permettront de
travailler sur les carrés des éléments d'un intervalle ou sur les nombres codice_70 de l'intervalle tels que codice_242
est vrai ou sur les nombres impairs de l'intervalle...
val carres_fold_right : (int -> 'a -> 'a) -> 'a -> int -> int -> 'a = <fun>
val filtre_fold_right :
 (int -> 'a -> 'a) -> (int -> bool) -> 'b -> 'a -> int -> int -> 'a = <fun>
val operation_sur_nombres_pairs_intervalle : (int -> 'a -> 'a) -> 'b -> 'a -> int -> int -> 'a =
 <fun>
val operation_sur_nombres_impairs_intervalle : (int -> 'a -> 'a) -> 'b -> 'a -> int -> int -> 'a =
 <fun> 
Cette possibilité d'abstraire des fonctions en des fonctions plus génériques qui seront plus tard spécialisées à l'aide d'arguments fonctionnels constitue l'un des avantages majeurs de la programmation fonctionnelle. On l'utilise notamment pour définir de nouveaux types de boucles sur des structures de données personnalisées -- tout comme ici sur les intervalles, les ensembles de nombres impairs, les ensembles de nombres impairs, etc. -- pour la gestion sûre des ressources externes, là où dans d'autres langages on emploierait codice_243, etc. Combiné avec la vérification de types d'OCaml, ceci permet de concevoir des bibliothèques sûres de manipulation de ressources et de structures de données.
Pour comparaison, en Java, cette notion d'intervalle s'écrirait de la manière suivante
//Définition de l'intervalle
public class Interval implements Iterable<Integer>
 //...
 public final int begin;
 public final int end;
 public Iterator<Integer> iterator ()
 return new IntervalIterator(this.begin, this.end);
//Définition de l'itération sur tous les entiers d'un intervalle d'entiers
public class IntervalIterator implements Iterator<Integer>
 private int current ;
 private final int end ;
 public IntervalIterator(int begin, int end)
 this.current = begin;
 this.end = end;
 public final Integer next ()
 if(this.current < this.end)
 return this.current++;
 else
 throw new NoSuchElementException(this.current);
 public void remove()
 this.current++;
 public bool hasNext()
 return this.current < this.next ;
//Calcul de la somme des entiers
public int sommeDesEntiers(int debut, int fin)
 int total = 0;
 for(Integer i : new Interval(debut, fin))
 total += i;
 return total;
Ajouter les filtres à cette version Java est possible mais compliquerait considérablement l'extrait.
D'autres langages, comme Python, emploient une syntaxe plus concise mais moins générique, spécialisée dans la définition de boucles sur les structures de données : les "générateurs". Tout ceci est aussi disponible en OCaml, sous le nom d"'énumérations", et sera détaillé plus tard.
Exercices.
Pour ce faire, vous réutiliserez codice_246.
Limitations et précautions.
Affichage de fonctions.
Comme nous l'avons noté, OCaml n'affiche jamais une fonction. En effet, les fonctions sont compilées immédiatement et leur représentation lisible oubliée. Après cela, il reste uniquement possible de consulter le type de la fonction.
Comparaison de fonctions.
En OCaml, deux fonctions ne peuvent jamais être comparées à l'aide des opérateurs codice_40, codice_41, codice_43, codice_44, codice_42, codice_45 :
Exception: Invalid_argument "equal: functional value".
La raison à cette limitation est à l'intersection du monde des mathématiques et de celui de l'informatique. En effet, rappelons que, mathématiquement, si nous avons
formula_16
alors, par définition,
formula_17
. En d'autres termes, pour comparer deux fonctions, il ne suffit pas de vérifier si elles ont été écrites de la même manière, mais il faut tester chacune des deux fonctions avec toutes les valeurs possibles. Ceci n'est pas faisable sur les machines actuelles -- et ne sera probablement jamais faisable, à moins que les machines quantiques fassent un jour leur apparition. Plutôt que de fournir une demi-solution, les programmeurs OCaml ont préféré jeter l'éponge et abandonner les comparaisons entre fonctions.
Malheureusement, l'analyseur de types d'OCaml n'est pas assez puissant pour déterminer lors de la compilation si l'opérateur codice_40 va être appliqué à deux fonctions. Cette vérification ne peut donc être effectuée que durant l'exécution, à l'instar des vérifications dynamiques de Java, C# ou de celles, omniprésentes, de Python, Ruby ou JavaScript.
Il reste possible de vérifier l'égalité physique entre deux fonctions à l'aide de l'opérateur codice_261. Cet opérateur, dont la sémantique est similaire à celle du même opérateur en Java, permet de vérifier si deux valeurs sont exactement la même (et non pas si elles ont le même résultat), comme suit :
- : bool = true
- : bool = false
- : bool = true
Modulo.
L'opérateur codice_16 n'est pas associé à une fonction codice_263. Il s'agit probablement du seul opérateur OCaml à ne pas être traduit sous la forme d'une fonction portant le même nom. Sans entrer dans les détails pour le moment, tous les autres opérateurs OCaml sont gérés par le même mécanisme d'analyse syntaxique, alors que codice_16 dispose d'un mécanisme pour lui seul.
Il s'agit d'une irrégularité mineure dans le langage OCaml. Il semble probable que cette irrégularité sera corrigée dans la prochaine version majeure, dans laquelle la gestion des opérateurs est en cours de révision.
Couples d'arguments.
Le premier réflexe d'un programmeur habitué à un autre langage de programmation est généralement de définir une fonction à plusieurs arguments avec la syntaxe suivante :
val multiplication_2 : (int * int) -> int = <fun>
Cette syntaxe est tout à fait légitime mais, comme on peut le constater en examinant le type du résultat, elle ne produit pas la même fonction que codice_99. En effet, le type de codice_99 place cette fonction dans l'ensemble formula_18, c'est-à-dire formula_19. À l'inverse, le type de codice_146 place cette fonction dans l'ensemble formula_20 ou encore formula_21. 
Ceci est du au fait que codice_268 représente, comme en mathématiques, le "couple" formula_22, pris dans l'ensemble formula_23, c'est-à-dire le type codice_269. En OCaml, on préférera généralement l'approche présentée avec codice_99, qui favorise la réutilisation et la composition de fonctions.
Mémoire des résultats.
Précisons que, par défaut, OCaml ne garde pas en mémoire les résultats d'un calcul. Ainsi, si l'on invoque 
- : int = 120
- : int = 720
Le calcul de codice_271 ne réutilisera aucun des résultats de codice_272. Ce comportement par défaut, commun à presque tous les langages de programmation (sauf Maple et quelques autres langages spécialisés dans les mathématiques), vise à éviter de gaspiller la mémoire vive à retenir des résultats qui seront a priori probablement inutiles. Il est cependant possible de demander à OCaml de conserver ces résultats en mémoire, c'est le processus de "mémoification". Nous verrons comment ajouter la mémoification dans le chapitre consacré à l'optimisation.
Profondeur de récursivité.
Généralement, une fonction récursive écrite de manière naïve consommera plus de mémoire vive qu'une boucle impérative, en raison de la nécessité de retenir des informations pour rassembler les résultats des sous-problèmes. En particulier, une telle boucle récursive, si elle est appelée sur un échantillon trop long, provoquera un "débordement de pile", c'est-à-dire une erreur fatale qui interrompra le calcul. Si la situation est moins grave que dans beaucoup de langages de programmation, grâce à la faible consommation de mémoire de OCaml, on cherchera à tirer le plus possible parti de la notion de "boucles récursives terminales", que le compilateur OCaml est capable d'optimiser pour supprimer ce problème.
Nous discuterons plus avant cette récursivité terminale dans le chapitre consacré à l'optimisation. Pour le moment, nous nous contenterons de la définition informelle suivante : une fonction est récursive terminale si le résultat est entièrement construit lors de la division en sous-problèmes et non pas dans une phase ultérieure de reconstitution.
Les boucles récursives terminales ont exactement le même pouvoir expressif que les boucles impératives.
À retenir.
désigne une erreur de typage : la fonction soulignée est appliquée à plus d'arguments qu'elle n'en accepte.
À propos de la programmation fonctionnelle.
Plus haut dans ce chapitre, nous avons défini la somme des nombres 
 if n < m then 0
 else m + ( somme_des_nombres ( m + 1 ) n ) ;;
val somme_des_nombres : int -> int -> int = <fun>
Comparons ceci à un équivalent écrit dans un langage impératif, ici Java :
public static int sommeDesNombres(int m, int n)
 int total = 0;
 for(int i = m; i <= n; ++i)
 total += i;
 return total;
Les deux extraits sont de taille sensiblement équivalente et beaucoup de programmeurs auront plus de facilité à lire le code Java, peut-être parce qu'ils ont généralement été formés sur des langages impératifs.
La philosophe impérative de Java recommande d'utiliser deux variables intermédiaires codice_276 et codice_209, dont la valeur va changer plusieurs fois au cours de l'exécution de la fonction. Au contraire, la philosophie fonctionnelle d'OCaml recommande de ne jamais réaffecter une valeur à une variable existante mais plutôt de se ramener au cas où la valeur de la variable est différente, de la même manière qu'en mathématiques -- ici en appelant récursivement la fonction codice_190. 
Dans l'absolu, aucune des deux philosophies n'est meilleure. L'une d'entre elles provient du monde de la Physique, dans lequel il est normal que l'état de l'univers change en permanence. L'autre provient du monde des Mathématiques, dans lesquelles le modèle est immuable mais on peut se placer dans des cas différents. Peut-être l'histoire de l'informatique aurait-elle été différente si les premiers programmeurs avaient été plus mathématiciens que physiciens, mais depuis la machine de Von Neumann le modèle sous-jacent à la partie électronique des ordinateurs est un modèle dans lequel l'univers change effectivement en permanence, sous la forme de modifications de la mémoire vive ou du disque dur. 
Employer l'approche physique/impérative permet de représenter naturellement des interactions avec le monde extérieur au programme (afficher quelque chose à l'écran ou sauvegarder un fichier, par exemple), qui n'ont pas de contrepartie simple en mathématiques. Cependant, comme c'est fréquemment le cas dès qu'il s'agit de l'interaction entre Physique et Mathématiques, si l'approche Physique permet d'avancer plus rapidement vers un résultat qui semble correct à première vue, l'approche Mathématique est nécessaire dès qu'il s'agit de s'assurer que les résultats sont effectivement corrects et réutilisables. Dans le monde de l'informatique, cela signifie qu'un développeur lambda produira souvent plus vite un programme impératif qu'un programme fonctionnel, mais qu'il sera plus difficile d'être certain que le programme fonctionne effectivement et que le programme sera fréquemment moins réutilisable. En effet, l'approche plus rigoureuse de la programmation fonctionnelle demandera au développeur plus de réflexion avant d'écrire son programme -- ou en tout cas avant d'arriver à le compiler -- mais vérifiera automatiquement plus de propriétés de sûreté et garantira par construction des propriétés telles que la réutilisabilité du code (un code qui ne modifie pas l'état de l'univers peut être utilisé dans n'importe quelles circonstances) ou l'optimisation du code (un code qui ne modifie pas l'état de l'univers peut être transformé en code parallèle, exécuté sur un autre microprocesseur ou un autre ordinateur, sans avoir à changer le reste du programme).
Encore une fois, cela ne signifie pas qu'une philosophie est meilleure que l'autre. Les deux états d'esprit sont nécessaires pour faire progresser un projet ou l'informatique dans son ensemble.
Bilan du chapitre.
Au cours de ce chapitre, nous avons couvert
Dans le prochain chapitre, nous allons couvrir plus en profondeur la notion de types et de structures de données.